#include "Wnd_ex.h"

LRESULT CALLBACK _wnd_defwindowprocW(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
    return DefWindowProcW(hWnd, Msg, wParam, lParam);
}

WORD Ex_WndRegisterClass(LPCWSTR lpwzClassName, HICON hIcon, HICON hIconsm, HCURSOR hCursor)
{
    WNDCLASSEXW WndClass = {0};
    WndClass.cbSize = sizeof(WNDCLASSEXW);
    WndClass.style = CS_VREDRAW | CS_HREDRAW | CS_DBLCLKS; //| CS_DBLCLKS
    WndClass.lpfnWndProc = _wnd_defwindowprocW;
    WndClass.hInstance = g_Li.hInstance;
    WndClass.hCursor = (hCursor == NULL ? g_Li.hCursor : hCursor);
    WndClass.hbrBackground = (HBRUSH)GetStockObject(NULL_BRUSH); //NULL_BRUSH
    WndClass.hIcon = (hIcon == NULL ? g_Li.hIcon : hIcon);
    WndClass.hIconSm = (hIconsm == NULL ? g_Li.hIconsm : hIconsm);
    WndClass.lpszClassName = lpwzClassName;
    return RegisterClassExW(&WndClass);
}

HEXDUI Ex_DUIFromWindow(HWND hWnd)
{
    return SendMessageW(hWnd, g_Li.dwMessage, EMV_HEXDUI, MAKELONG(EMT_DUI, 0));
}

BOOL _wnd_getfromhandle(size_t handle, HWND *hWnd, wnd_s **ppWnd, obj_s **ppObj, BOOL *isObject, INT *nError)
{
    if (isObject)
    {
        *isObject = FALSE;
    }
    if (IsWindow((HWND)handle))
        handle = Ex_DUIFromWindow((HWND)handle);

    wnd_s *pWnd = NULL;
    obj_s *pObj = NULL;

    if (_handle_validate(handle, HT_DUI, (LPVOID *)&pWnd, nError))
    {
        if (hWnd)
        {
            *hWnd = pWnd->hWnd_;
        }
        pObj = (obj_s *)pWnd;
    }
    else if (_handle_validate(handle, HT_OBJECT, (LPVOID *)&pObj, nError))
    {
        pWnd = (wnd_s *)pObj->pWnd_;
        if (hWnd)
        {
            *hWnd = pWnd->hWnd_;
        }
        if (isObject)
        {
            *isObject = TRUE;
        }
    }
    else
    {
        return FALSE;
    }
    if (ppWnd)
    {
        *ppWnd = pWnd;
    }
    if (ppObj)
    {
        *ppObj = pObj;
    }
    return TRUE;
}

LRESULT _wnd_dispatch_notify(HWND hWnd, wnd_s *pWnd, size_t hObj, INT nID, INT nCode, WPARAM wParam, LPARAM lParam, obj_s *pObj)
{
    WinMsgPROC pfnMsgProc = pWnd->pfnMsgProc_;
    LRESULT ret = 0;
    if (pfnMsgProc)
    {
        EX_NMHDR hdr;
        hdr.hObjFrom = hObj;
        hdr.idFrom = nID;
        hdr.lParam = lParam;
        hdr.nCode = nCode;
        hdr.wParam = wParam;
        pfnMsgProc(hWnd, pWnd->hexdui_, WM_NOTIFY, nID, (size_t)&hdr, &ret);
    }

    return ret;
}

void _wnd_redraw_bkg(HWND hWnd, wnd_s *pWnd, LPVOID lpRect, BOOL bRedrawBkg, BOOL bUpdate)
{
    if (bRedrawBkg)
    {
        pWnd->dwFlags_ = pWnd->dwFlags_ | EWF_BREDRAWBACKGROUND;
    }
    InvalidateRect(hWnd, (RECT *)lpRect, FALSE);
    if (bUpdate)
    {
        UpdateWindow(hWnd);
    }
}

BOOL _wnd_querystyle(HWND hWnd, INT dwStyle, BOOL bExStyle)
{
    return (GetWindowLongPtrW(hWnd, bExStyle ? GWL_EXSTYLE : GWL_STYLE) & dwStyle) != 0;
}

BOOL _wnd_delstyle(HWND hWnd, INT dwStyle, BOOL bExStyle)
{
    auto ret = GetWindowLongPtrW(hWnd, bExStyle ? GWL_EXSTYLE : GWL_STYLE);
    if ((ret & dwStyle) != 0)
    {
        ret &= ~dwStyle;
        SetWindowLongPtrW(hWnd, bExStyle ? GWL_EXSTYLE : GWL_STYLE, ret);
        return TRUE;
    }
    return FALSE;
}

BOOL _wnd_addstyle(HWND hWnd, INT dwStyle, BOOL bExStyle)
{
    auto ret = GetWindowLongPtrW(hWnd, bExStyle ? GWL_EXSTYLE : GWL_STYLE);
    if ((ret & dwStyle) == 0)
    {
        SetWindowLongPtrW(hWnd, bExStyle ? GWL_EXSTYLE : GWL_STYLE, ret | dwStyle);
        return TRUE;
    }
    return FALSE;
}

LRESULT _wnd_defaultproc(HWND hWnd, INT uMsg, WPARAM wParam, LPARAM lParam)
{
    return DefWindowProcW(hWnd, uMsg, wParam, lParam);
}

HICON _wnd_geticonhandle(HWND hWnd, BOOL isbigicon)
{
    HICON ret = (HICON)SendMessageW(hWnd, WM_GETICON, (isbigicon ? 1 : 0), 0);
    if (ret == 0)
    {
        ret = (HICON)GetClassLongPtrW(hWnd, isbigicon ? GCLP_HICON : GCLP_HICONSM);
    }
    return ret;
}

LPVOID Thunkwindow(HWND hWnd, ThunkPROC pfnProc, LPVOID dwData, INT *nError)
{
#ifdef _WIN64
    CHAR shellcode[] = "\x48\xB9\x00\x00\x00\x00\x00\x00\x00\x00\x48\xB8\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xE0";
    /*
16970E90000 - 48 B9 0000000000000000 - mov rcx,0000000000000000
16970E9000A - 48 B8 0000000000000000 - mov rax,0000000000000000
16970E90014 - FF E0                 - jmp rax
		*/
#else
    CHAR shellcode[] = "\xC7\x44\x24\x04\x00\x00\xC4\x0E\xE9\x73\x47\x09\xF2";
    /*
00970000 - C7 44 24 04 0000C40E  - mov [esp+04],0EC40000
00970008 - E9 734709F2           - jmp F2A04780
		*/
#endif

    size_t len = sizeof(shellcode) + sizeof(EX_THUNK_DATA);
    EX_THUNK_DATA *lpData = (EX_THUNK_DATA *)VirtualAlloc(0, len, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);

    if (lpData != NULL)
    {
        lpData->hWnd = hWnd;
        lpData->Proc = (WNDPROC)GetWindowLongPtr(hWnd, GWLP_WNDPROC);
        lpData->dwData = dwData;

        CHAR *lpCode = (CHAR *)(lpData + 1); // lpData + 1 是指向结构体末尾
        RtlMoveMemory(lpCode, shellcode, sizeof(shellcode));
#ifdef _WIN64
        *((PUINT64)(lpCode + 2)) = (UINT64)lpData;
        *((PUINT64)(lpCode + 12)) = (UINT64)pfnProc;
#else
        *((PUINT32)(lpCode + 4)) = (UINT32)lpData;
        *((PUINT32)(lpCode + 9)) = (UINT32)((UINT32)pfnProc - (UINT32)lpCode - 13);
#endif // _WIN64

        FlushInstructionCache(GetCurrentProcess(), lpData, len);
        SetWindowLongPtrW(hWnd, GWLP_WNDPROC, (size_t)lpCode);
    }
    else
        *nError = GetLastError();
    return lpData;
}

BOOL _wnd_getscreenrect(HWND hWnd, RECT *rcMonitor, RECT *rcDesk)
{
    BOOL ret = FALSE;
    HMONITOR hMonitor = MonitorFromWindow(hWnd, 2);
    if (hMonitor != 0)
    {
        MONITORINFO info = {0};
        info.cbSize = 40;
        if (GetMonitorInfoW(hMonitor, &info))
        {
            if (rcMonitor)
            {
                *rcMonitor = info.rcMonitor;
            }
            if (rcDesk)
            {
                *rcDesk = info.rcWork;
            }
            ret = TRUE;
        }
    }
    if (!ret)
    {
        Ex_SetLastError(GetLastError());
    }
    return ret;
}

std::wstring _wnd_gettitle(HWND hWnd) //OK
{
    auto len = SendMessageW(hWnd, WM_GETTEXTLENGTH, 0, 0);
    len = (len + 1) * 2;
    std::wstring ret;
    ret.resize(len);
    SendMessageW(hWnd, WM_GETTEXT, len, (LPARAM)(ret.data()));
    return ret;
}

INT _wnd_classtoatom(HWND hWnd) //OK
{
    std::wstring ret;
    ret.resize(64);
    GetClassNameW(hWnd, (LPWSTR)ret.data(), 64);
    return Ex_Atom(ret.data());
}

INT _wnd_getfunctionkeys() //OK
{
    INT ret = 0;
    if ((GetAsyncKeyState(VK_CONTROL) & 32768) != 0)
    {
        ret = ret | 1;
    }
    if ((GetAsyncKeyState(VK_SHIFT) & 32768) != 0)
    {
        ret = ret | 2;
    }
    if ((GetAsyncKeyState(VK_MENU) & 32768) != 0)
    {
        ret = ret | 4;
    }
    return ret;
}

void Ex_WndCenterFrom(HWND hWnd, HWND hWndFrom, BOOL bFullScreen)
{
    RECT rcWindow, rcParent;
    GetWindowRect(hWnd, &rcWindow);
    if (hWndFrom == 0)
    {
        if (bFullScreen)
        {
            _wnd_getscreenrect(hWnd, &rcParent);
        }
        else
        {
            _wnd_getscreenrect(hWnd, NULL, &rcParent);
        }
    }
    else
    {
        GetWindowRect(hWndFrom, &rcParent);
    }
    SetWindowPos(hWnd, 0, rcParent.left + (rcParent.right - rcParent.left - (rcWindow.right - rcWindow.left)) / 2, rcParent.top + (rcParent.bottom - rcParent.top - (rcWindow.bottom - rcWindow.top)) / 2, 0, 0, SWP_NOSIZE);
}

WPARAM Ex_WndMsgLoop()
{
    MSG msg = {0};
    while (GetMessageW(&msg, 0, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessageW(&msg);
    }
    return msg.wParam;
}

HWND Ex_WndCreate(HWND hWndParent, LPCWSTR lpwzClassName, LPCWSTR lpwzWindowName, INT x, INT y, INT width, INT height, INT dwStyle, INT dwStyleEx)
{
    if (dwStyle == 0)
    {
        dwStyle = WS_OVERLAPPEDWINDOW;
    }

    if (dwStyleEx == 0)
    {
        dwStyleEx = WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE;
    }
    if ((dwStyle & WS_CHILD) != WS_CHILD)
    {
        dwStyleEx = dwStyleEx | WS_EX_LAYERED;
    }

    if (lpwzClassName == 0)
    {
        lpwzClassName = (LPCWSTR)g_Li.atomClassName;
    }

    HINSTANCE hInst = g_Li.hInstance;
    if (IsWindow(hWndParent))
    {
        hInst = (HINSTANCE)GetWindowLongPtrW(hWndParent, GWLP_HINSTANCE);
    }

    HWND hWnd = CreateWindowExW(dwStyleEx, lpwzClassName, lpwzWindowName, dwStyle, x, y, width, height, hWndParent, NULL, hInst, NULL);
    if (hWnd != 0)
    {
        SendMessageW(hWnd, 128, 0, (LPARAM)g_Li.hIconsm);
        SendMessageW(hWnd, 128, 1, (LPARAM)g_Li.hIcon);
    }
    return hWnd;
}

void _wnd_recalcclient(wnd_s *pWnd, HWND hWnd, INT width, INT height)
{
    pWnd->width_ = width;
    pWnd->height_ = height;
    if (_canvas_resize(pWnd->canvas_display_, width, height))
    {
        if (_canvas_resize(pWnd->canvas_bkg_, width, height)) //客户区被改变,必定触发背景被改变事件
        {
            pWnd->dwFlags_ = pWnd->dwFlags_ | EWF_BREDRAWBACKGROUND;
        }
    }
    _rgn_destroy(pWnd->hrgn_client_);
    _rgn_destroy(pWnd->hrgn_sizebox_);
    INT nSizebox = 0;

    if (((pWnd->dwStyle_ & EWS_SIZEABLE) == EWS_SIZEABLE))
    {
        nSizebox = 5;
    }
    LPVOID hRgnClient = _rgn_createfromrect(nSizebox, nSizebox, width - nSizebox, height - nSizebox);
    pWnd->hrgn_client_ = hRgnClient;
    if (nSizebox != 0)
    {
        LPVOID hRgnNC = _rgn_createfromrect(0, 0, width, height);
        LPVOID hRgnSizebox = _rgn_combine(hRgnNC, hRgnClient, RGN_COMBINE_EXCLUDE, 0, 0);
        _rgn_destroy(hRgnNC);
        pWnd->hrgn_sizebox_ = hRgnSizebox;
    }
}

BOOL _wnd_wm_stylechanging(wnd_s *pWnd, HWND hWnd, WPARAM wParam, LPARAM lParam)
{
    BOOL ret = FALSE;
    INT styleNew = __get_int((LPVOID)lParam, 4);
    INT styleDui = pWnd->dwStyle_;

    if (wParam == GWL_EXSTYLE)
    {
        
        if (((pWnd->dwStyle_ & EWS_MESSAGEBOX) == EWS_MESSAGEBOX))
        {
            pWnd->dwFlags_ = pWnd->dwFlags_ | EWF_BLAYERED;
        }
        else
        {
            if (__query_int((LPVOID)lParam, 4, WS_EX_LAYERED)) //待定有问题
            {
                
                pWnd->dwFlags_ = pWnd->dwFlags_ - (pWnd->dwFlags_ & EWF_BLAYERED);
            }
            else
            {
                if (((pWnd->dwFlags_ & EWF_BLAYERED) == EWF_BLAYERED))
                {
                    pWnd->dwFlags_ = pWnd->dwFlags_ - (pWnd->dwFlags_ & EWF_BLAYERED);
                }
            }
        }
        InvalidateRect(hWnd, NULL, FALSE);
    }
    else
    {
        styleNew = (styleNew & ~(WS_DLGFRAME | WS_BORDER));
        if ((styleDui & EWS_BUTTON_MIN) == 0 || (styleDui & EWS_FULLSCREEN) == EWS_FULLSCREEN)
        {
            styleNew = (styleNew & ~WS_MINIMIZEBOX);
        }
        else
        {
            styleNew = styleNew | WS_MINIMIZEBOX;
        }

        if ((styleDui & EWS_BUTTON_MAX) == 0 || (styleDui & EWS_FULLSCREEN) == EWS_FULLSCREEN)
        {
            styleNew = (styleNew & ~WS_MAXIMIZEBOX);
        }
        else
        {
            styleNew = styleNew | WS_MAXIMIZEBOX;
        }

        if ((styleDui & EWS_FULLSCREEN) == EWS_FULLSCREEN)
        {
            styleNew = (styleNew & ~WS_SYSMENU);
        }
        else
        {
            styleNew = styleNew | WS_SYSMENU;
        }

        if ((styleDui & EWS_SIZEABLE) == EWS_SIZEABLE)
        {
            styleNew = styleNew | WS_THICKFRAME;
        }
        else
        {
            styleNew = styleNew & ~WS_THICKFRAME;
        }

        if (styleNew != ((STYLESTRUCT*)lParam)->styleNew)
        {
            ((STYLESTRUCT*)lParam)->styleNew = styleNew;
            ret = TRUE;
        }
    }
    return ret;
}

void _wnd_loadtheme(wnd_s *pWnd, HWND hWnd, HEXTHEME hTheme)
{

    EXATOM atom = ((pWnd->dwStyle_ & EWS_MENU) == EWS_MENU) ? ATOM_DUIMENU : ATOM_WINDOW;
    LPVOID pPADDING_SHADOW = Ex_ThemeGetValuePtr(hTheme, atom, ATOM_PADDING_SHADOW);
    if (pPADDING_SHADOW != 0)
    {
        pWnd->padding_shadow_ = pPADDING_SHADOW;
        pWnd->minWidth_ = Ex_Scale(__get_int(pPADDING_SHADOW, 0) + __get_int(pPADDING_SHADOW, 8));
        pWnd->minHeight_ = Ex_Scale(__get_int(pPADDING_SHADOW, 4) + __get_int(pPADDING_SHADOW, 8));
    }
    LPVOID pSIZE = Ex_ThemeGetValuePtr(hTheme, atom, ATOM_SIZE);

    if (pSIZE != 0)
    {
        pWnd->size_caption_ = pSIZE;
    }
    LPVOID pMARGIN = Ex_ThemeGetValuePtr(hTheme, atom, ATOM_MARGIN);

    if (pMARGIN != 0)
    {
        pWnd->margin_caption_ = pMARGIN;
    }

    LPVOID pBACKGROUND_COLOR = Ex_ThemeGetValuePtr(hTheme, atom, ATOM_BACKGROUND_COLOR);

    if (pBACKGROUND_COLOR != 0)
    {

        pWnd->crBkg_ = __get_int(pBACKGROUND_COLOR, 0);
    }
    //菜单
    LPVOID pPADDING_CLIENT = Ex_ThemeGetValuePtr(hTheme, ATOM_DUIMENU, ATOM_PADDING_CLIENT);
    if (pPADDING_CLIENT != 0)
    {
        pWnd->padding_client_ = pPADDING_CLIENT;
    }
    LPVOID pPADDING_TEXT = Ex_ThemeGetValuePtr(hTheme, ATOM_DUIMENU, ATOM_PADDING_TEXT);
    if (pPADDING_TEXT != 0)
    {
        pWnd->padding_text_ = pPADDING_TEXT;
    }
    LPVOID pPADDING_SEPARATOR = Ex_ThemeGetValuePtr(hTheme, ATOM_DUIMENU, ATOM_PADDING_SEPARATOR);
    if (pPADDING_SEPARATOR != 0)
    {
        pWnd->padding_separator_ = pPADDING_SEPARATOR;
    }
    LPVOID pSIZE_ITEM = Ex_ThemeGetValuePtr(hTheme, ATOM_DUIMENU, ATOM_SIZE_ITEM);
    WORD szItem = 0;
    if (pSIZE_ITEM != 0)
    {
        szItem = MAKEWORD(__get_int(pSIZE_ITEM, 0), __get_int(pSIZE_ITEM, 4));
    }
    LPVOID pSIZE_SEPARATOR = Ex_ThemeGetValuePtr(hTheme, ATOM_DUIMENU, ATOM_SIZE_SEPARATOR);
    WORD szSeparator = 0;
    if (pSIZE_SEPARATOR != 0)
    {
        szSeparator = MAKEWORD(__get_int(pSIZE_SEPARATOR, 0), __get_int(pSIZE_SEPARATOR, 4));
    }

    pWnd->szItemSeparator_ = MAKELONG(szItem, szSeparator);
    LPVOID lpFontFamily = nullptr;
    INT dwFontSize = -1;
    INT dwFontStyle = -1;
    LPVOID pFONT_SIZE = Ex_ThemeGetValuePtr(hTheme, ATOM_ITEM, ATOM_FONT_SIZE);
    if (pFONT_SIZE != 0)
    {
        dwFontSize = __get_int(pFONT_SIZE, 0);
    }
    LPVOID pFONT_STYLE = Ex_ThemeGetValuePtr(hTheme, ATOM_ITEM, ATOM_FONT_STYLE);
    if (pFONT_STYLE != 0)
    {
        dwFontStyle = __get_int(pFONT_STYLE, 0);
    }
    LPVOID pFONT_FAMILY = Ex_ThemeGetValuePtr(hTheme, ATOM_ITEM, ATOM_FONT_FAMILY);
    if (pFONT_FAMILY != 0)
    {
        lpFontFamily = pFONT_FAMILY;
    }

    HEXFONT pfont = _font_createfromfamily((LPWSTR)lpFontFamily, dwFontSize, dwFontStyle);

    if (pfont != 0)
    {
        _font_destroy(pWnd->hFont_Menu_);
        pWnd->hFont_Menu_ = pfont;
    }
    _wnd_recalcclient(pWnd, hWnd, pWnd->width_, pWnd->height_);
}

void _wnd_calc_captionrect(wnd_s *pWnd, RECT *rcCaption)
{
    LPVOID lpValue = pWnd->size_caption_;
    if (lpValue != 0)
    {
        (*rcCaption).right = __get_int(lpValue, 0) / 100 * pWnd->width_; //保证百分比
        (*rcCaption).bottom = Ex_Scale(__get_int(lpValue, 4));           //绝对高度
    }
    lpValue = pWnd->margin_caption_;
    if (lpValue != 0)
    {
        (*rcCaption).left = Ex_Scale(__get_int(lpValue, 0));
        (*rcCaption).top = Ex_Scale(__get_int(lpValue, 4));
        (*rcCaption).right = (*rcCaption).right - Ex_Scale(__get_int(lpValue, 8));
    }
    (*rcCaption).bottom = (*rcCaption).bottom + (*rcCaption).top;
}

void CALLBACK _wnd_backgroundimage_timer_inherit(HWND hWnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
{
   // KillTimer(hWnd, idEvent);
    wnd_s *pWnd = (wnd_s *)(idEvent - TIMER_BKG_INHERIT);

    if (!((pWnd->dwStyle_ & EWS_NOINHERITBKG) == EWS_NOINHERITBKG))
    {
        wnd_s *ppWnd = nullptr;
        INT nError = 0;
        if (_handle_validate(pWnd->hExDuiParent_, HT_DUI, (LPVOID *)&ppWnd, &nError))
        {
            EX_BACKGROUNDIMAGEINFO *lpBI = (EX_BACKGROUNDIMAGEINFO *)ppWnd->lpBackgroundImage_;
            if (lpBI)
            {
                INT *pDelay = (INT *)lpBI->lpDelay;
                if (pDelay != 0)
                {
                    _wnd_redraw_bkg(hWnd, pWnd, 0, TRUE, FALSE);
                    UpdateWindow(hWnd);
                    //SetTimer(hWnd, idEvent, pDelay[lpBI->curFrame] * 10, _wnd_backgroundimage_timer_inherit);
                }
            }
        }
    }
}

size_t _wnd_dispatch_msg(HWND hWnd, wnd_s *pWnd, INT uMsg, WPARAM wParam, LPARAM lParam)
{
    INT16 nType = LOWORD(lParam);
    size_t ret = 0;
    if (nType == EMT_OBJECT) //组件消息
    {
        ret = _wnd_dispatch_msg_obj(hWnd, (mempoolmsg_s *)wParam, 0, 0, 0, 0);
    }
    else if (nType == EMT_DUI) //窗体消息
    {
        if (wParam == EMV_HEXDUI)
        {
            return pWnd->hexdui_;
        }
        else if (wParam == EMV_PFN_PACK)
        {
            ///////////return (size_t)(&_res_pack);
        }
    }
    else if (nType >= WM_MOUSEFIRST && nType <= WM_MOUSELAST || nType >= NIN_SELECT && nType <= NIN_BALLOONUSERCLICK)
    {
        _wnd_dispatch_notify(hWnd, pWnd, pWnd->hexdui_, -1, NM_TRAYICON, wParam, lParam, 0);
    }
    else if (nType == EMT_LAYOUT_UPDATE)
    {
        _layout_update(wParam);
    }
    else if (nType == EMT_EASING)
    {
        _wnd_dispatch_notify(hWnd, pWnd, pWnd->hexdui_, -1, NM_EASING, __get((LPVOID)wParam, 0), wParam, 0);
    }
    return ret;
}

size_t _wnd_dispatch_msg_obj(HWND hWnd, mempoolmsg_s *lpData, obj_s *pObj, INT uMsg, WPARAM wParam, LPARAM lParam)
{
    size_t ret = 0;
    if (MemPool_AddressIsUsed(lpData))
    {
        pObj = lpData->pObj;
        uMsg = lpData->uMsg;
        wParam = lpData->wParam;
        lParam = lpData->lParam;
        if (pObj)
        {
            ret = _obj_msgproc(hWnd, pObj->hObj_, pObj, uMsg, wParam, lParam);
        }
        MemPool_Free(g_Li.hMemPoolMsg, lpData);
    }
    return ret;
}

LRESULT CALLBACK _wnd_proc(EX_THUNK_DATA *pData, INT uMsg, WPARAM wParam, LPARAM lParam)
{
    HWND hWnd = pData->hWnd;
    WNDPROC pOld = pData->Proc;
    wnd_s *pWnd = (wnd_s *)pData->dwData;
    WinMsgPROC pfnMsgProc = pWnd->pfnMsgProc_;
    if (pfnMsgProc != 0)
    {
        LRESULT ret = 0;
        if (pfnMsgProc(hWnd, pWnd->hexdui_, uMsg, wParam, lParam, &ret) != 0)
        {
            return ret;
        }
    }

    if (uMsg == g_Li.dwMessage)
    {
        return _wnd_dispatch_msg(hWnd, pWnd, uMsg, wParam, lParam);
    }
    else if (uMsg == WM_NCHITTEST) //132
    {
        return _wnd_wm_nchittest(pWnd, hWnd, lParam);
    }
    else if (uMsg == WM_SETCURSOR) //32
    {
        if (_wnd_wm_setcursor(hWnd, pWnd, lParam))
        {
            return 1;
        }
    }
    else if (uMsg == WM_CLOSE)
    {
        HWND hwndParent = (HWND)GetWindowLongPtrW(hWnd, GWLP_HWNDPARENT); //防止消息框子窗口或组合框子窗口关闭使主窗口失去激活
        if (hwndParent)
        {
            if (GetActiveWindow() != hwndParent)
            {
                SetActiveWindow(hwndParent);
            }
        }
    }
    else if (uMsg == WM_DESTROY)
    {
        if (_wnd_destroy(hWnd, pWnd) != 0)
        {
            PostQuitMessage(0);
        }
        SetWindowLongPtrW(hWnd, GWLP_WNDPROC, (size_t)pOld);
        VirtualFree(pData, 0, MEM_RELEASE);
    }
    else if (uMsg == WM_ERASEBKGND)
    {
        return 1;
    }
    else if (uMsg == WM_SIZE)
    {
        INT width = LOWORD(lParam);
        INT height = HIWORD(lParam);
        _wnd_wm_size(pWnd, hWnd, wParam, width, height);
    }
    else if (uMsg == WM_WINDOWPOSCHANGING) //70
    {
        if (((pWnd->dwStyle_ & EWS_MENU) == EWS_MENU))
        {
            tagWINDOWPOS *pos = (tagWINDOWPOS *)lParam;
            if (!(pos->flags & SWP_NOSIZE))
            {
                LPVOID padding_client = pWnd->padding_client_;
                if (padding_client != 0)
                {
                    pos->cy += Ex_Scale(__get_int(padding_client, 4) + __get_int(padding_client, 12));
                }
            }

            if ((pos->flags & SWP_NOMOVE) != SWP_NOMOVE) //被移动了
            {

                if (GetWindow(hWnd, GW_OWNER) != 0) //子菜单
                {

                    pWnd->pMenuHostWnd_->dwFlags_ = pWnd->pMenuHostWnd_->dwFlags_ - (pWnd->pMenuHostWnd_->dwFlags_ & EWF_BMENUREPOSTION);
                    _wnd_menu_setpos(hWnd, pWnd, pos);
                }
                pWnd->left_ = pos->x;
                pWnd->top_ = pos->y;
                _wnd_menu_init(hWnd, pWnd);
                return 0;
            }
        }
    }
    else if (uMsg == WM_WINDOWPOSCHANGED) //71
    {
        tagWINDOWPOS *pos = (tagWINDOWPOS *)lParam;
        if (!(pos->flags & SWP_NOMOVE))
        {
            pWnd->left_ = pos->x;
            pWnd->top_ = pos->y;
            _wnd_paint_shadow(pWnd, FALSE, FALSE);
        }
    }
    else if (uMsg == WM_NCCALCSIZE) //131
    {
        return 0;
    }
    else if (uMsg == WM_NCACTIVATE) //134
    {
        obj_s Obj;
        _wnd_wm_leavecheck(hWnd, pWnd, pWnd->objHittest_, -1, &Obj, lParam, TRUE);
        if (wParam == 0)
        {
            HEXOBJ focus = pWnd->objFocus_;
            pWnd->dwFlags_ = pWnd->dwFlags_ - (pWnd->dwFlags_ & EWF_ACTIVE);
            pWnd->objFocusPrev_ = focus;
            Ex_ObjKillFocus(focus);
        }
        else
        {
            pWnd->dwFlags_ = pWnd->dwFlags_ | EWF_ACTIVE;
            HEXOBJ focus = pWnd->objFocusPrev_;
            Ex_ObjSetFocus(focus);
            pWnd->objFocusPrev_ = 0;
        }
        _wnd_paint_shadow(pWnd, FALSE, TRUE);
        if (wParam == 0)
        {
            if (lParam == (size_t)(pWnd->hWndShadow_))
            {
                if (((pWnd->dwStyle_ & EWS_MESSAGEBOX) == EWS_MESSAGEBOX))
                {

                    return 0;
                }
            }
        }
        return 1; //防止出现边框/系统按钮
    }
    else if (uMsg == WM_NCPAINT) //133
    {
        return 0;
    }
    else if (uMsg == WM_MOUSEACTIVATE)
    { //防止弹出窗获取焦点
        if (FLAGS_CHECK(pWnd->dwStyle_, EWS_POPUPWINDOW))
        {
            return MA_NOACTIVATE;
        }
    }
    else if (uMsg == WM_NCLBUTTONDOWN)
    {
        _wnd_popupclose(pWnd, hWnd, 0, 0);
    }
    else if (uMsg == WM_PAINT) //15
    {
        if (_wnd_wm_paint(pWnd, hWnd))
        {
            return 0;
        }
    }
    else if (uMsg == WM_SHOWWINDOW) //24
    {
        if (wParam == 0)
        {
            HEXOBJ objHittest = pWnd->objHittest_;
            if (objHittest != 0)
            {
                Ex_ObjDispatchMessage(objHittest, WM_MOUSELEAVE, 0, 0);
                pWnd->objHittest_ = 0;
                UpdateWindow(hWnd);
            }
        }
        HWND hWndShadow = pWnd->hWndShadow_;
        if (!_wnd_querystyle(hWnd, WS_EX_TOPMOST, TRUE))
        {
            SetWindowPos(hWndShadow, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOREDRAW | SWP_NOSENDCHANGING | SWP_NOACTIVATE);
        }
        ShowWindow(hWndShadow, wParam == 0 ? 0 : SW_SHOWNOACTIVATE);
        InvalidateRect(hWnd, NULL, FALSE);
    }
    else if (uMsg == WM_GETMINMAXINFO) //36
    {
        if (_wnd_wm_getminmaxinfo(pWnd, hWnd, lParam))
        {
            return 0;
        }
    }
    else if (uMsg == WM_STYLECHANGING) //124
    {
        if (_wnd_wm_stylechanging(pWnd, hWnd, wParam, lParam))
        {
            return 0;
        }
    }
    else if (uMsg == WM_MOUSEWHEEL) //522  WM_MOUSEFIRST到WM_MOUSELAST包含了WM_MOUSEWHEEL，因此要在下一个判断之前拦截。
    {
        _wnd_wm_mousewheel(hWnd, pWnd, uMsg, wParam, lParam);
    }
    else if (uMsg >= WM_MOUSEFIRST && uMsg < WM_MOUSELAST) //512 - 526
    {
        _wnd_wm_mouse(pWnd, hWnd, uMsg, wParam, lParam);
    }
    else if (uMsg >= WM_KEYFIRST && uMsg <= WM_KEYLAST) //256,264
    {
        _wnd_wm_keyboard(pWnd, hWnd, uMsg, wParam, lParam);
    }
    else if (uMsg == WM_CAPTURECHANGED) //533
    {
        _wnd_wm_captionchange(hWnd, pWnd, lParam);
    }
    else if (uMsg == WM_CONTEXTMENU) //被动接受消息123
    {
        _wnd_wm_menucontext(hWnd, pWnd, uMsg, wParam, lParam);
    }
    else if (uMsg == WM_SYSCOMMAND || uMsg == WM_COMMAND) //274,273
    {
        _wnd_wm_command(hWnd, pWnd, uMsg, wParam, lParam);
    }
    else if (uMsg == WM_ENTERSIZEMOVE) //561
    {
        pWnd->dwFlags_ = pWnd->dwFlags_ | EWF_BSIZEMOVING;
    }
    else if (uMsg == WM_EXITSIZEMOVE) //562
    {
        pWnd->dwFlags_ = pWnd->dwFlags_ - (pWnd->dwFlags_ & EWF_BSIZEMOVING);
    }
    else if (uMsg == WM_MEASUREITEM) //44
    {
        if (_wnd_wm_measureitem_host(pWnd, wParam, lParam))
        {
            return 1;
        }
    }
    else if (uMsg == WM_INITDIALOG) //272
    {
        if (((pWnd->dwStyle_ & EWS_MESSAGEBOX) == EWS_MESSAGEBOX))
        {
            _msgbox_initdialog(hWnd, pWnd, wParam, lParam);
            auto ret = CallWindowProcW(pOld, hWnd, uMsg, wParam, lParam);
            SetFocus(hWnd);
            return ret;
        }
    }
    else if (uMsg == WM_GETDLGCODE) //135
    {
        if (((pWnd->dwFlags_ & EWF_BMODAL) == EWF_BMODAL))
        {
            return (DLGC_WANTARROWS | DLGC_WANTTAB | DLGC_WANTALLKEYS | DLGC_WANTMESSAGE | DLGC_HASSETSEL | DLGC_WANTCHARS);
        }
    }
    else if (uMsg == WM_INITMENUPOPUP) //279
    {
        if (((pWnd->dwStyle_ & EWS_MENU) == EWS_MENU))
        {
            return 0;
        }
        _wnd_wm_initmenupopup(hWnd, pWnd, (HMENU)wParam);
    }
    else if (uMsg == WM_EXITMENULOOP) //530
    {
        if (((pWnd->dwStyle_ & EWS_MENU) == EWS_MENU))
        {
            return 0;
        }
        pWnd->dwFlags_ = pWnd->dwFlags_ - (pWnd->dwFlags_ & EWF_BMENUINITED);
        size_t objHittest = pWnd->objHittest_;
        _wnd_wm_nchittest(pWnd, hWnd, -1);
        obj_s Obj;
        _wnd_wm_leavecheck(hWnd, pWnd, objHittest, -1, &Obj, lParam, TRUE);
        pWnd->dx_counts_ = 0;
    }
    else if (uMsg == WM_IME_COMPOSITION) //271
    {
        _wnd_wm_ime_composition(hWnd, pWnd);
    }
    else if (uMsg == WM_SETTEXT) //12
    {
        if (((pWnd->dwStyle_ & EWS_TITLE) == EWS_TITLE))
        {
            Ex_ObjSendMessage(_obj_getobjfromidorname(pWnd, EWS_TITLE), uMsg, wParam, lParam);
        }
    }
    else if (uMsg == MN_SELECTITEM) // MN_SELECTITEM
    {
        if (((pWnd->dwFlags_ & EWF_BTRACKOBJECT) == EWF_BTRACKOBJECT))
        {
            POINT pt;
            GetCursorPos(&pt);
            _wnd_wm_mouse(pWnd, hWnd, WM_MOUSEMOVE, 1, MAKELONG(pt.x - pWnd->left_, pt.y - pWnd->top_));
            return 0;
        }
        else
        {
            LONG_PTR item = 0;
            _wnd_menu_mouse(hWnd, pWnd, WM_MOUSEMOVE, 0, (LONG_PTR *)&wParam);
            if (LODWORD(wParam) == -1)
            {
                return 0;
            }
            else
            {

                wnd_s *pMenuHostWnd = pWnd->pMenuHostWnd_;
                if (pMenuHostWnd != 0)
                {
                    pMenuHostWnd->pMenuPrevWnd_ = pWnd;
                }
            }
        }
    }
    else if (uMsg == 0x1E6) //MN_CANCELMENUS
    {
        wnd_s *pMenuHostWnd = pWnd->pMenuHostWnd_;
        if (pMenuHostWnd != 0)
        {
            wnd_s *pMenuTrackWnd = pMenuHostWnd->pMenuTrackWnd_;
            if (pMenuTrackWnd != 0)
            {
                if (((pMenuTrackWnd->dwFlags_ & EWF_BTRACKOBJECT) == EWF_BTRACKOBJECT))
                {
                    _wnd_obj_untrack(pMenuTrackWnd->hWnd_, pMenuTrackWnd, lParam, TRUE);
                    return CallWindowProcW(pOld, hWnd, 0x1EF, -1, 0);
                }
            }
        }
    }
    else if (uMsg == 0x1ED) //MN_BUTTONDOWN
    {
        if (!_wnd_menu_mouse(hWnd, pWnd, WM_LBUTTONDOWN, 1, (LONG_PTR *)&wParam))
        {
            return CallWindowProcW(pOld, hWnd, uMsg, -1, lParam);
        }

        if (((pWnd->dwFlags_ & EWF_BTRACKOBJECT) != EWF_BTRACKOBJECT))
        {
            return CallWindowProcW(pOld, hWnd, uMsg, -1, lParam);
        }
    }
    else if (uMsg == 0x1EF) //MN_BUTTONUP
    {
        _wnd_menu_mouse(hWnd, pWnd, WM_LBUTTONUP, 0, (LONG_PTR *)&wParam);
        if (pWnd->objTrackPrev_ != pWnd->objHittest_)
        {
            return CallWindowProcW(pOld, hWnd, uMsg, -1, lParam);
        }
    }
    else if (uMsg == 0x01F1) //MN_DBLCLK
    {
        return 0;
    }
    else if (uMsg == WM_COPY)
    {
        if (_wnd_wm_keyboard(pWnd, hWnd, uMsg, wParam, lParam))
        {
            return 1;
        }
    }
    else if (uMsg == WM_IME_CHAR)
    {
        if (_wnd_wm_keyboard(pWnd, hWnd, uMsg, wParam, lParam))
        {
            return 1;
        }
    }
    return CallWindowProcW(pOld, hWnd, uMsg, wParam, lParam);
}

INT _wnd_create(HEXDUI hExDui, wnd_s *pWnd, HWND hWnd, INT dwStyle, HEXTHEME hTheme, LPARAM lParam, WinMsgPROC lpfnMsgProc)
{
    ShowWindow(hWnd, 0);
    RECT rcWindow{0};
    GetWindowRect(hWnd, &rcWindow);
    SIZE size;
    size.cx = rcWindow.right - rcWindow.left;
    size.cy = rcWindow.bottom - rcWindow.top;

    if (!FLAGS_CHECK(dwStyle, EWS_MESSAGEBOX) && !FLAGS_CHECK(dwStyle, EWS_COMBOWINDOW))
    {
        INT offsetX = 0;
        INT offsetY = 0;
        if (Flag_Query(EXGF_DPI_ENABLE))
        {
            size.cx = Ex_Scale(size.cx);
            size.cy = Ex_Scale(size.cy);
            offsetX = (size.cx - (rcWindow.right - rcWindow.left)) / 2;
            offsetY = (size.cy - (rcWindow.bottom - rcWindow.top)) / 2;
        }
        MoveWindow(hWnd, rcWindow.left - offsetX, rcWindow.top - offsetY, size.cx, size.cy, FALSE);
    }
    HWND hWndParent = 0;
    if ((dwStyle & EWS_MESSAGEBOX) == EWS_MESSAGEBOX)
    {
        _wnd_getfromhandle(((mbp_s *)lParam)->handle_, &hWndParent);
    }
    else
    {

        hWndParent = (HWND)GetWindowLongPtrW(hWnd, GWLP_HWNDPARENT);
    }
    if ((dwStyle & EWS_CENTERWINDOW) == EWS_CENTERWINDOW)
    {
        Ex_WndCenterFrom(hWnd, hWndParent, (dwStyle & EWS_FULLSCREEN) != 0);
    }

    GetWindowRect(hWnd, &rcWindow);
    size.cx = rcWindow.right - rcWindow.left;
    size.cy = rcWindow.bottom - rcWindow.top;
    INT dwFlags = 0;

    if (_wnd_querystyle(hWnd, WS_EX_LAYERED, TRUE) || ((dwStyle & EWS_MESSAGEBOX) == EWS_MESSAGEBOX))
    {
        
        dwFlags = EWF_BLAYERED;
    }
   
    if (hWndParent != 0)
    {
        pWnd->hExDuiParent_ = Ex_DUIFromWindow(hWndParent);
    }
    auto atomName = GetClassLongPtrW(hWnd, GCW_ATOM);
    if (atomName == ATOM_DIALOG)
    {
        dwFlags = dwFlags | EWF_BMODAL;
        dwFlags = dwFlags | EWF_ACTIVE;
    }
    if (hTheme == 0)
        hTheme = g_Li.hThemeDefault;

    pWnd->dwStyle_ = dwStyle;
    pWnd->hImc_ = ImmGetContext(hWnd);
    pWnd->hWnd_ = hWnd;
    pWnd->hexdui_ = hExDui;
    pWnd->hTheme_ = hTheme;
    pWnd->width_ = size.cx;
    pWnd->height_ = size.cy;
    pWnd->alpha_ = 255;
    pWnd->dwFlags_ = dwFlags | EWF_BLEAVESENT;
    pWnd->pfnMsgProc_ = lpfnMsgProc;
    pWnd->hTableObjects_ = HashTable_Create(GetNearestPrime(256), NULL);

    pWnd->hTableEvent_ = HashTable_Create(17, pfnDefaultFreeData);

    if ((dwStyle & EWS_MESSAGEBOX) != 0)
    {
        pWnd->lpMsgParams_ = (mbp_s *)lParam;
    }
    else
    {
        pWnd->lParam_ = lParam;
    }

    //layer
    pWnd->ulwi_.pptDst = (POINT *)((size_t)pWnd + offsetof(wnd_s, left_));
    pWnd->ulwi_.psize = (SIZE *)((size_t)pWnd + offsetof(wnd_s, width_));
    pWnd->ulwi_.pptSrc = (POINT *)((size_t)pWnd + offsetof(wnd_s, ulwi_pptSrc_x_));
    pWnd->ulwi_.pblend = (BLENDFUNCTION *)((size_t)pWnd + offsetof(wnd_s, ulwi_pblend_));
    pWnd->ulwi_.prcDirty = (RECT *)((size_t)pWnd + offsetof(wnd_s, ulwi_prcDirty_left_));

    pWnd->ulwi_.cbSize = sizeof(pWnd->ulwi_);
    pWnd->ulwi_.dwFlags = 2;
    pWnd->ulwi_pblend_.AlphaFormat = 1;
    pWnd->ulwi_pblend_.BlendFlags = 0;
    pWnd->ulwi_pblend_.BlendOp = 0;
    pWnd->ulwi_pblend_.SourceConstantAlpha = 0xFF;
    pWnd->left_ = rcWindow.left;
    pWnd->top_ = rcWindow.top;
    pWnd->width_ = size.cx;
    pWnd->height_ = size.cy;
    pWnd->ulwi_prcDirty_right_ = size.cx;
    pWnd->ulwi_prcDirty_bottom_ = size.cy;

    //sysshadow
    auto style = GetClassLongPtrW(hWnd, GCL_STYLE);
    if ((style & CS_DROPSHADOW) != 0)
    {
        SetClassLongPtrW(hWnd, GCL_STYLE, (style & ~CS_DROPSHADOW));
    }
    INT exStyle = WS_EX_TOOLWINDOW | WS_EX_LAYERED | WS_EX_TRANSPARENT | WS_EX_NOACTIVATE | WS_EX_TOPMOST;
    HWND hwndShadow = CreateWindowExW(exStyle, (LPCWSTR)g_Li.atomSysShadow, 0, WS_POPUP, 0, 0, 0, 0, hWnd, 0, 0, 0);

    pWnd->hWndShadow_ = hwndShadow;
    INT nError = 0;
    Thunkwindow(hwndShadow, _wnd_shadow_proc, (LPVOID)1, &nError);
    //tips
    HWND hWndTips = CreateWindowExW(WS_EX_TOOLWINDOW | WS_EX_NOACTIVATE | WS_EX_TOPMOST, L"tooltips_class32", 0, WS_POPUP, 0, 0, 0, 0, 0, 0, 0, 0);
    SendMessageW(hWndTips, 1048, 0, 2048); //TTM_SETMAXTIPWIDTH 支持多行
    pWnd->hWndTips_ = hWndTips;
    nError = 0;
    ti_s *toolauto = (ti_s *)_struct_createfromaddr(pWnd, offsetof(wnd_s, ti_auto_), sizeof(ti_s), &nError);

    toolauto->cbSize_ = sizeof(ti_s);
    toolauto->uFlags_ = 16 | 256 | 4096; //TTF_SUBCLASS,TTF_TRANSPARENT,TTF_PARSELINKS
    toolauto->hWnd_ = hWnd;
    toolauto->uId_ = toolauto;
    SendMessageW(hWndTips, 1074, 0, (LPARAM)toolauto); //TTM_ADDTOOLW
    nError = 0;
    ti_s *tooltrack = (ti_s *)_struct_createfromaddr(pWnd, offsetof(wnd_s, ti_track_), sizeof(ti_s), &nError);

    tooltrack->cbSize_ = sizeof(ti_s);
    tooltrack->uFlags_ = 32 | 128 | 256 | 4096; //TTF_TRACK,TTF_ABSOLUTE,TTF_TRANSPARENT,TTF_PARSELINKS
    tooltrack->hWnd_ = hWnd;
    tooltrack->uId_ = tooltrack;
    SendMessageW(hWndTips, 1074, 0, (LPARAM)tooltrack); //TTM_ADDTOOLW
    nError = 0;
    Thunkwindow(hWndTips, _wnd_tooltips_proc, pWnd, &nError);

    //初始化渲染,以及背景
    _wnd_dx_init(pWnd);
    INT w1, h1;
    w1 = rcWindow.right - rcWindow.left;
    h1 = rcWindow.bottom - rcWindow.top;
    nError = 0;
    pWnd->canvas_display_ = _canvas_createfrompwnd(pWnd, w1, h1, ECVF_GDI_COMPATIBLE, &nError);

    nError = 0;
    pWnd->canvas_bkg_ = _canvas_createfrompwnd(pWnd, w1, h1, 0, &nError);

    if (nError == 0)
    {
        //加载主题，并确定客户区

        _wnd_loadtheme(pWnd, hWnd, hTheme);

        if ((dwStyle & EWS_MENU) == 0)
        {
            _wnd_sysbutton_create(hWnd, pWnd, dwStyle);
        }

        _wnd_addstyle(hWnd, WS_THICKFRAME, FALSE); //强制触发样式被修改事件
        Thunkwindow(hWnd, _wnd_proc, pWnd, &nError);
        _wnd_delstyle(hWnd, WS_THICKFRAME, FALSE);
        IME_Control(hWnd, pWnd, FALSE);

        if (FLAGS_CHECK(dwStyle, EWS_POPUPWINDOW))
        {
            pWnd->lpPopupParams_ = lParam;
            if (_handle_validate(pWnd->hExDuiParent_, HT_DUI, (LPVOID *)&pWnd, &nError))
            {
                HWND old = pWnd->hWndPopup_;
                pWnd->hWndPopup_ = hWnd;
                DestroyWindow(old);
                FLAGS_ADD(pWnd->dwFlags_, EWF_BPOPUPWINDOIWSHOWN);
                obj_s *pObj;
                if (_handle_validate(lParam, HT_OBJECT, (LPVOID *)&pObj, &nError))
                {
                    _obj_baseproc(hWndParent, lParam, pObj, -6, hExDui, 0);
                    IME_Control(hWndParent, pWnd, TRUE);
                }
            }
            nError = 0;
        }
    }

    return nError;
}

LRESULT CALLBACK _wnd_tooltips_proc(EX_THUNK_DATA *pData, INT uMsg, WPARAM wParam, LPARAM lParam)
{
    HWND hWnd = pData->hWnd;
    WNDPROC pOld = pData->Proc;
    wnd_s *pWnd = (wnd_s *)pData->dwData;
    if (uMsg == WM_DESTROY)
    {
        SetWindowLongPtrW(hWnd, GWLP_WNDPROC, (size_t)pOld);
        VirtualFree(pData, 0, MEM_RELEASE);
    }
    else if (uMsg == WM_LBUTTONDOWN || uMsg == WM_RBUTTONDOWN)
    {
        lParam = CallWindowProcW(pOld, hWnd, uMsg, wParam, lParam);
        SendMessageW(hWnd, 1041, 0, (size_t)pWnd + offsetof(wnd_s, ti_track_));
        return lParam;
    }
    return CallWindowProcW(pOld, hWnd, uMsg, wParam, lParam);
}

LRESULT CALLBACK _wnd_shadow_proc(EX_THUNK_DATA *pData, INT uMsg, WPARAM wParam, LPARAM lParam)
{

    HWND hWnd = pData->hWnd;
    size_t pOld = (size_t)pData->Proc;

    if (uMsg == WM_NCACTIVATE)
    {
        size_t hWndParent = GetWindowLongPtrW(hWnd, GWLP_HWNDPARENT);
        if (!(wParam == 0 && lParam == hWndParent))
        {
            if ((WPARAM)pData->dwData == wParam && lParam == 0)
            {
                SendMessageW((HWND)hWndParent, uMsg, 1, lParam);
                SetFocus((HWND)hWndParent);
                pData->dwData = (LPVOID)1;
                return 0;
            }
            SendMessageW((HWND)hWndParent, uMsg, wParam, lParam);
            pData->dwData = (LPVOID)wParam;
        }
    }
    else if (uMsg == WM_DESTROY)
    {

        SetWindowLongPtrW(hWnd, GWLP_WNDPROC, pOld);
        VirtualFree(pData, 0, MEM_RELEASE);
    }
    return CallWindowProcW((WNDPROC)pOld, hWnd, uMsg, wParam, lParam);
}

void _wnd_dx_unint(wnd_s *pWnd)
{
    ID2D1DeviceContext *pDeviceContext = pWnd->dx_context_;

    if (pDeviceContext)
    {
        pDeviceContext->Release();
    }
    ID2D1GdiInteropRenderTarget *pgdiinterop = pWnd->dx_gdiinterop_;
    if (pgdiinterop)
    {
        pgdiinterop->Release();
    }
}

void _wnd_dx_init(wnd_s *pWnd)
{
    _wnd_dx_unint(pWnd);
    ID2D1DeviceContext *pDeviceContext = nullptr;
    if (g_Ri.pD2DDevice->CreateDeviceContext(D2D1_DEVICE_CONTEXT_OPTIONS_NONE, &pDeviceContext) == 0)
    {
        pDeviceContext->SetUnitMode(D2D1_UNIT_MODE_PIXELS);
        pWnd->dx_context_ = pDeviceContext;
        pWnd->dx_gdiinterop_ = _dx_get_gdiInterop(pDeviceContext);
    }
}

HEXOBJ _wnd_wm_nchittest_obj(HWND hWnd, wnd_s *pWnd, HEXOBJ objLast, INT x, INT y, INT *hitCode, obj_s **pObjMouse)
{
    HEXOBJ objPrev = objLast;
    obj_s *pObj = nullptr;
    INT nError = 0;
    while (_handle_validate(objPrev, HT_OBJECT, (LPVOID *)&pObj, &nError))
    {

        if (((pObj->dwStyle_ & EOS_VISIBLE) == EOS_VISIBLE))
        {
            RECT rt = {pObj->left_, pObj->top_, pObj->right_, pObj->bottom_};
            POINT po = {x, y};
            if (PtInRect(&rt, po))
            {
                INT ox = x - pObj->left_;
                INT oy = y - pObj->top_;
                auto lParam = MAKELONG(ox, oy);

                if (((pObj->dwStyle_ & EOS_DISABLED) == EOS_DISABLED)) //检测是否被禁止，被禁止组件还需检测是否可穿透
                {
                    *hitCode = _obj_baseproc(hWnd, objPrev, pObj, WM_NCHITTEST, 0, lParam);
                    if (*hitCode == HTTRANSPARENT) //在穿透区域,则继续寻找
                    {
                        objPrev = pObj->objPrev_;
                        continue;
                    }
                    else
                    {
                        *hitCode = HTCLIENT; //不可穿透则直接停止寻找
                        *pObjMouse = pObj;
                        return objPrev;
                    }
                }
                else
                {
                    objLast = pObj->objChildLast_;
                    if (objLast != 0)
                    {
                        auto ret = _wnd_wm_nchittest_obj(hWnd, pWnd, objLast, ox, oy, hitCode, pObjMouse);
                        if (ret != 0 && *hitCode != HTTRANSPARENT) //找到目标子组件
                        {
                            return ret;
                        }
                    }
                }
                *hitCode = _obj_baseproc(hWnd, objPrev, pObj, WM_NCHITTEST, 0, lParam);
                if (*hitCode == HTTRANSPARENT) // 如果可穿透，则继续寻找
                {
                    objPrev = pObj->objPrev_;
                    continue;
                }
                else
                {
                    pWnd->dwHitObjPos_Abs_ = lParam;
                    *pObjMouse = pObj;
                    return objPrev;
                }
            }
        }
        objPrev = pObj->objPrev_;
    }
    return 0;
}

INT _wnd_wm_nchittest_sizebox(INT width, INT height, INT x, INT y)
{
    INT ret = 0;
    INT nOffset = 5 * 2;
    if (y < nOffset) //鼠标在顶部
    {
        if (x < nOffset) //鼠标在左边
        {
            ret = HTTOPLEFT;
        }
        else if (x > width - nOffset) //鼠标在右边
        {

            ret = HTTOPRIGHT;
        }
        else
        {
            ret = HTTOP;
        }
    }
    else
    {
        if (y > height - nOffset) //鼠标在底部
        {
            if (x < nOffset) //鼠标在左边
            {
                ret = HTBOTTOMLEFT;
            }
            else if (x > width - nOffset) //鼠标在右边
            {
                ret = HTBOTTOMRIGHT;
            }
            else
            {
                ret = HTBOTTOM;
            }
        }
        else
        {
            if (x < nOffset) //鼠标在左边
            {
                if (y < nOffset) //鼠标在上面
                {
                    ret = HTTOPLEFT;
                }
                else
                {
                    if (y > height - nOffset) //鼠标在下面
                    {
                        ret = HTBOTTOMLEFT;
                    }
                    else
                    {
                        ret = HTLEFT;
                    }
                }
            }
            else
            {
                //鼠标在右边
                if (y < nOffset) //鼠标在上面
                {
                    ret = HTTOPRIGHT;
                }
                else
                {
                    if (y > height - nOffset) //鼠标在下面
                    {
                        ret = HTBOTTOMRIGHT;
                    }
                    else
                    {
                        ret = HTRIGHT;
                    }
                }
            }
        }
    }
    return ret;
}

INT _wnd_wm_nchittest(wnd_s *pWnd, HWND hWnd, LPARAM lParam)
{
    INT dwHitCode = HTCLIENT;

    if (((pWnd->dwFlags_ & EWF_BTRACKOBJECT) == EWF_BTRACKOBJECT))
        return dwHitCode;

    if (!((pWnd->dwStyle_ & EWS_MENU) == EWS_MENU))
    {

        if (((pWnd->dwFlags_ & EWF_BMENUINITED) == EWF_BMENUINITED))
        {
            return dwHitCode;
        }
    }

    POINT pt;
    HEXOBJ objMouse = 0;
    if (lParam == -1)
    {
        GetCursorPos(&pt);
    }
    else
    {
        pt.x = GET_X_LPARAM(lParam);
        pt.y = GET_Y_LPARAM(lParam);
    }
    ScreenToClient(hWnd, &pt);
    if (_rgn_hittest(pWnd->hrgn_client_, pt.x, pt.y) || pWnd->dwWinState_ == 2)
    {
        obj_s *pobjMouse = nullptr;
        objMouse = _wnd_wm_nchittest_obj(hWnd, pWnd, pWnd->objChildLast_, pt.x, pt.y, &dwHitCode, &pobjMouse);
        if (objMouse == 0)
        {
            pobjMouse = 0;

            if (((pWnd->dwStyle_ & EWS_MOVEABLE) == EWS_MOVEABLE)) //允许随意移动
            {
                dwHitCode = HTCAPTION;
            }
        }
        else
        {
            pWnd->dwHitCode_ = dwHitCode;
            if (objMouse == pWnd->objCaption_)
            {
                dwHitCode = HTCAPTION;
            }
            else
            {

                if (((pobjMouse->dwStyle_ & EOS_DISABLED) == EOS_DISABLED))
                {

                    if (((pWnd->dwStyle_ & EWS_MOVEABLE) == EWS_MOVEABLE)) //允许随意移动
                    {
                        dwHitCode = HTCAPTION;
                    }
                    objMouse = 0;
                }
            }
        }
    }
    else
    {
        //在尺寸边框内

        if (((pWnd->dwStyle_ & EWS_SIZEABLE) == EWS_SIZEABLE)) //允许调整尺寸
        {
            dwHitCode = _wnd_wm_nchittest_sizebox(pWnd->width_, pWnd->height_, pt.x, pt.y);
        }
        else
        {
            dwHitCode = HTCAPTION;
        }
    }

    auto objHittest = pWnd->objHittest_;
    pWnd->objHittest_ = objMouse;
    if (objHittest != objMouse)
    {
        pWnd->objHittestPrev_ = objHittest;
        dwHitCode = HTCLIENT;
    }
    return dwHitCode;
}

void _wnd_sysbutton_create(HWND hWnd, wnd_s *pWnd, INT dwStyle)
{
    HEXTHEME hTheme = pWnd->hTheme_;
    RECT rcCaption = {0};
    _wnd_calc_captionrect(pWnd, &rcCaption);
    obj_s *pObjCaption = nullptr;
    INT nError = 0;
    HEXOBJ objCaption = _obj_create_init(hWnd, pWnd, ATOM_SYSBUTTON, 0, &pObjCaption, &nError);

    INT nMinHeight = 0;
    if (objCaption != 0)
    {
        std::wstring title;
        LPCWSTR lpTitle = nullptr;

        if (((pWnd->dwStyle_ & EWS_MESSAGEBOX) == EWS_MESSAGEBOX))
        {

            lpTitle = pWnd->lpMsgParams_->lpCaption_;
        }
        else
        {

            title = _wnd_gettitle(hWnd);
            lpTitle = title.data();
        }

        _obj_create_proc(&nError, FALSE, hTheme, pObjCaption, (dwStyle & EWS_NOCAPTIONTOPMOST) != 0 ? 0 : -1, ATOM_SYSBUTTON, lpTitle,
                         EOS_VISIBLE | EWS_TITLE, rcCaption.left, rcCaption.top, rcCaption.right - rcCaption.left, rcCaption.bottom - rcCaption.top, 0, EWS_TITLE, 0, 0, DT_LEFT | DT_VCENTER | DT_SINGLELINE);

        LPVOID lpPT = Ex_ThemeGetValuePtr(hTheme, ATOM_WINDOW, ATOM_PADDING_TEXT);
        if (lpPT != 0)
        {
            RtlMoveMemory((LPVOID)((size_t)pObjCaption + offsetof(obj_s, t_left_)), lpPT, 16);

            if (g_Li.DpiX > 1)
            {
                pObjCaption->t_left_ = pObjCaption->t_left_ * g_Li.DpiX;
                pObjCaption->t_top_ = pObjCaption->t_top_ * g_Li.DpiX;
                pObjCaption->t_right_ = pObjCaption->t_right_ * g_Li.DpiX;
                pObjCaption->t_bottom_ = pObjCaption->t_bottom_ * g_Li.DpiX;
            }
        }
        LPVOID lpCr = Ex_ThemeGetValuePtr(hTheme, ATOM_WINDOW, ATOM_COLOR_NORMAL);
        if (lpCr != 0)
        {
            pObjCaption->crNormal_ = __get_int(lpCr, 0);
        }
        LPVOID pFamily = Ex_ThemeGetValuePtr(hTheme, ATOM_WINDOW, ATOM_FONT_FAMILY);
        LPVOID pSize = Ex_ThemeGetValuePtr(hTheme, ATOM_WINDOW, ATOM_FONT_SIZE);
        LPVOID pStyle = Ex_ThemeGetValuePtr(hTheme, ATOM_WINDOW, ATOM_FONT_STYLE);

        INT Size, Style;
        if (pFamily == 0)
            pFamily = (LPVOID)-1;
        if (pSize == 0)
        {
            Size = -1;
        }
        else
        {
            Size = __get_int(pSize, 0);
        }
        if (pStyle == 0)
        {
            Style = -1;
        }
        else
        {
            Style = __get_int(pStyle, 0);
        }
        if ((size_t)pFamily != -1 || Size != -1 || Style != -1)
        {
            HEXFONT hfont = pObjCaption->hFont_;

            pObjCaption->hFont_ = _font_createfromfamily((LPWSTR)pFamily, Size, Style);

            if (hfont != 0)
                _font_destroy(hfont);
        }

        _obj_create_done(hWnd, pWnd, objCaption, pObjCaption);
        pWnd->objCaption_ = objCaption;
        nMinHeight = rcCaption.bottom + rcCaption.top;
    }
    std::vector<INT> aryBtn = {EWS_BUTTON_CLOSE, EWS_BUTTON_MAX, EWS_BUTTON_MIN, EWS_BUTTON_MENU, EWS_BUTTON_SKIN, EWS_BUTTON_SETTING, EWS_BUTTON_HELP};
    std::vector<INT> aryAtom = {ATOM_SYSBUTTON_CLOSE, ATOM_SYSBUTTON_MAX, ATOM_SYSBUTTON_MIN, ATOM_SYSBUTTON_MENU, ATOM_SYSBUTTON_SKN, ATOM_SYSBUTTON_SETTING, ATOM_SYSBUTTON_HELP};
    INT left = rcCaption.right - rcCaption.left;
    INT nMinWidth = 0;

    for (INT i = 0; i < 7; i++)
    {
        if ((dwStyle & aryBtn[i]) != 0)
        {

            LPVOID lpValuea = Ex_ThemeGetValuePtr(hTheme, aryAtom[i], ATOM_NORMAL);

            if (lpValuea != 0)
            {

                RECT rcObject{0};
                RtlMoveMemory(&rcObject, lpValuea, 16);
                rcObject.right = Ex_Scale(rcObject.right - rcObject.left);
                rcObject.bottom = Ex_Scale(rcObject.bottom - rcObject.top);

                left = left - rcObject.right;
                obj_s *pObjTmp = nullptr;
                INT nError = 0;
                HEXOBJ objTmp = _obj_create_init(hWnd, pWnd, ATOM_SYSBUTTON, 0, &pObjTmp, &nError);
                if (objTmp != 0)
                {

                    _obj_create_proc(&nError, FALSE, hTheme, pObjTmp, -1, ATOM_SYSBUTTON, 0, EOS_VISIBLE | aryBtn[i], left, 0, rcObject.right, rcObject.bottom, objCaption, aryBtn[i], 0, 0, 0);
                    _obj_create_done(hWnd, pWnd, objTmp, pObjTmp);
                    nMinWidth = nMinWidth + rcObject.right;
                }
            }
        }
    }
    pObjCaption->t_right_ = pObjCaption->t_right_ + nMinWidth;
    nMinWidth = nMinWidth + rcCaption.left + pWnd->width_ - rcCaption.right;

    if (((pWnd->dwStyle_ & EWS_HASICON) == EWS_HASICON))
    {
        nMinWidth = nMinWidth + Ex_Scale(16);
    }
    if (pWnd->minWidth_ < nMinWidth)
    {
        pWnd->minWidth_ = nMinWidth;
    }
    if (pWnd->minHeight_ < nMinHeight)
    {
        pWnd->minHeight_ = nMinHeight;
    }
}

void _wnd_render_obj(HWND hWnd, wnd_s *pWnd, ID2D1DeviceContext *pContext, HEXCANVAS cvDisplay, LPVOID pBitmapDisplay, RECT rcPaint,
                     EXHANDLE objChildFirst, INT offsetX, INT offsetY, INT pAlpha, BOOL fDX, LPVOID hBorderBrush)
{
    EXHANDLE objNext = objChildFirst;
    INT nError = 0;
    if (objNext != 0)
    {
        do
        {
            obj_s *pObj = nullptr;
            if (_handle_validate(objNext, HT_OBJECT, (LPVOID *)&pObj, &nError))
            {

                if (((pObj->dwStyle_ & EOS_VISIBLE) == EOS_VISIBLE))
                {
                    RECT rcObj{0};
                    rcObj.left = pObj->left_;
                    rcObj.top = pObj->top_;
                    rcObj.right = pObj->right_;
                    rcObj.bottom = pObj->bottom_;

                    OffsetRect(&rcObj, offsetX, offsetY);
                    RECT rcClip{0};
                    if (IntersectRect(&rcClip, &rcPaint, &rcObj))
                    {

                        auto fPage = (pObj->dwFlags_ & EOF_BPAGE) != EOF_BPAGE;
                        if (fPage)
                        {

                            if (((pObj->dwFlags_ & EOF_BCANREDRAW) == EOF_BCANREDRAW))
                            {

                                if (((pObj->dwFlags_ & EOF_BNEEDREDRAW) == EOF_BNEEDREDRAW))
                                {
                                    pObj->dwFlags_ = pObj->dwFlags_ - (pObj->dwFlags_ & EOF_BNEEDREDRAW);
                                    if (!IsRectEmpty((RECT *)((size_t)pObj + offsetof(obj_s, d_left_))))
                                    {
                                        _obj_baseproc(hWnd, objNext, pObj, WM_PAINT, 0, 0);
                                        if (fDX)
                                        {
                                            _dx_settarget(pContext, (ID2D1Bitmap *)pBitmapDisplay);
                                        }
                                    }
                                }
                            }
                        }
                        //组件透明度是否需要被窗口透明度影响？？
                        INT alpha = pObj->dwAlpha_ * pWnd->alpha_ / 255;
                        alpha = alpha * pAlpha / 255;

                        if (((pObj->dwStyle_ & EOS_DISABLED) == EOS_DISABLED))
                        {
                            alpha = alpha * pObj->dwAlphaDisable_ / 255;
                        }
                        if (fPage) //非页面
                        {

                            if (((pObj->dwFlags_ & EOF_BPATH) == EOF_BPATH))
                            {
                                LPVOID hPathBrush = _brush_createfromcanvas2(pObj->canvas_obj_, alpha);
                                if (hPathBrush != 0)
                                {
                                    HEXMATRIX matrix = _matrix_create();
                                    _matrix_translate(matrix, pObj->w_left_, pObj->w_top_);
                                    _brush_settransform(hPathBrush, matrix);
                                    _canvas_fillpath(cvDisplay, pObj->hPath_Window_, hPathBrush);
                                    _brush_destroy(hPathBrush);
                                    _matrix_destroy(matrix);
                                }
                            }
                            else
                            {

                                if (((pObj->dwStyleEx_ & EOS_EX_COMPOSITED) == EOS_EX_COMPOSITED))
                                {
                                    _canvas_bitblt(cvDisplay, pObj->canvas_obj_, rcClip.left, rcClip.top, rcClip.right, rcClip.bottom, rcClip.left - rcObj.left, rcClip.top - rcObj.top);
                                }
                                else
                                {
                                    _canvas_alphablend(cvDisplay, pObj->canvas_obj_, rcClip.left, rcClip.top, rcClip.right, rcClip.bottom, rcClip.left - rcObj.left, rcClip.top - rcObj.top, rcClip.right - rcObj.left, rcClip.bottom - rcObj.top, alpha);
                                }
                            }
                        }
                        if (hBorderBrush != 0)
                        {
                            _canvas_drawrect(cvDisplay, hBorderBrush, pObj->w_left_, pObj->w_top_, pObj->w_right_, pObj->w_bottom_, 1, D2D1_DASH_STYLE_SOLID);
                        }

                        HEXOBJ objChild = pObj->objChildFirst_;
                        if (objChild != 0)
                        {
                            _wnd_render_obj(hWnd, pWnd, pContext, cvDisplay, pBitmapDisplay, rcClip, objChild, rcObj.left, rcObj.top, alpha, fDX, hBorderBrush);
                        }
                    }
                }
            }
            else
            {
                break;
            }
            objNext = pObj->objNext_;
        } while (objNext != 0);
    }
}

BOOL _wnd_wm_setcursor(HWND hWnd, wnd_s *pWnd, LPARAM lParam)
{
    auto uHitCode = LOWORD(lParam);
    auto hCursor = pWnd->hCursor_;
    if (uHitCode == HTCLIENT)
    {
        auto objHittest = pWnd->objHittest_;
        obj_s *pObj = nullptr;
        INT nError = 0;
        if (_handle_validate(objHittest, HT_OBJECT, (LPVOID *)&pObj, &nError))
        {
            if (_obj_baseproc(hWnd, objHittest, pObj, WM_SETCURSOR, pWnd->dwHitObjPos_Abs_, MAKELONG(pWnd->dwHitCode_, HIWORD(lParam))) != 0)
            {
                return TRUE;
            }
        }
    }
    else if (uHitCode == HTCAPTION)
    {
        hCursor = g_Li.hCursor;
    }
    else if (uHitCode == HTTOPLEFT)
    {
        hCursor = LoadCursorW(0, IDC_SIZENWSE);
    }
    else if (uHitCode == HTTOPRIGHT)
    {
        hCursor = LoadCursorW(0, IDC_SIZENESW);
    }
    else if (uHitCode == HTTOP)
    {
        hCursor = LoadCursorW(0, IDC_SIZENS);
    }
    else if (uHitCode == HTBOTTOMLEFT)
    {
        hCursor = LoadCursorW(0, IDC_SIZENESW);
    }
    else if (uHitCode == HTBOTTOMRIGHT)
    {
        hCursor = LoadCursorW(0, IDC_SIZENWSE);
    }
    else if (uHitCode == HTBOTTOM)
    {
        hCursor = LoadCursorW(0, IDC_SIZENS);
    }
    else if (uHitCode == HTTOPLEFT)
    {
        hCursor = LoadCursorW(0, IDC_SIZENWSE);
    }
    else if (uHitCode == HTBOTTOMLEFT)
    {
        hCursor = LoadCursorW(0, IDC_SIZENESW);
    }
    else if (uHitCode == HTLEFT)
    {
        hCursor = LoadCursorW(0, IDC_SIZEWE);
    }
    else if (uHitCode == HTTOPRIGHT)
    {
        hCursor = LoadCursorW(0, IDC_SIZENESW);
    }
    else if (uHitCode == HTBOTTOMRIGHT)
    {
        hCursor = LoadCursorW(0, IDC_SIZENWSE);
    }
    else if (uHitCode == HTRIGHT)
    {
        hCursor = LoadCursorW(0, IDC_SIZEWE);
    }

    if (hCursor != 0)
    {
        SetCursor((HCURSOR)hCursor);
        return TRUE;
    }
    return FALSE;
}

void CALLBACK _wnd_timer_mousetrack(HWND hWnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
{
    KillTimer(hWnd, idEvent);
    wnd_s *pWnd = (wnd_s *)(idEvent - TIMER_MOUSETRACK);

    if ((pWnd->dwFlags_ & EWF_BTRACKOBJECT) != EWF_BTRACKOBJECT)
    {
        POINT pt;
        GetCursorPos(&pt);
        if (WindowFromPoint(pt) != hWnd)
        {
            if ((pWnd->dwFlags_ & EWF_BLEAVESENT) != EWF_BLEAVESENT)
            {
                pWnd->dwFlags_ = pWnd->dwFlags_ | EWF_BLEAVESENT;
                HEXOBJ hObj = pWnd->objHittestPrev_;
                obj_s *pObj = nullptr;
                INT nError = 0;
                if (_handle_validate(hObj, HT_OBJECT, (LPVOID *)&pObj, &nError))
                {
                    _obj_baseproc(hWnd, hObj, pObj, WM_MOUSELEAVE, 0, 0); //发送离开
                    pWnd->objHittestPrev_ = pWnd->objHittest_;
                    pWnd->objHittest_ = 0;
                }
            }
        }
    }
}

void _wnd_wm_leavecheck(HWND hWnd, wnd_s *pWnd, HEXOBJ objCheck, HEXOBJ objHittest, obj_s *pObjHittest, LPARAM lParam, BOOL fTrack)
{
    INT nError = 0;
    if (objHittest == -1)
    {
        objHittest = pWnd->objHittest_;
        _handle_validate(objHittest, HT_OBJECT, (LPVOID *)&pObjHittest, &nError);
    }
    if (objCheck != objHittest)
    {
        nError = 0;
        obj_s *pObjCheck = nullptr;
        if (_handle_validate(objCheck, HT_OBJECT, (LPVOID *)&pObjCheck, &nError))
        {

            if ((pWnd->dwFlags_ & EWF_BLEAVESENT) != EWF_BLEAVESENT)
            {
                pWnd->dwFlags_ = pWnd->dwFlags_ | EWF_BLEAVESENT;
                _obj_baseproc(hWnd, objCheck, pObjCheck, WM_MOUSELEAVE, 0, lParam);
            }
        }
        if (objHittest != 0)
        {
            pWnd->dwFlags_ = pWnd->dwFlags_ - (pWnd->dwFlags_ & EWF_BLEAVESENT);
            pWnd->objHittestPrev_ = objHittest;
            _obj_baseproc(hWnd, objHittest, pObjHittest, WM_MOUSEHOVER, 0, lParam);
        }
    }

    if (objHittest != 0 && fTrack)
    {
        size_t nEvent = (size_t)pWnd + TIMER_MOUSETRACK;
        KillTimer(hWnd, nEvent);
        SetTimer(hWnd, nEvent, 50, _wnd_timer_mousetrack);
    }
}

INT _wnd_destroy(HWND hWnd, wnd_s *pWnd)
{
    obj_s *pObj = nullptr;
    INT nError = 0;
    pWnd->dwFlags_ = pWnd->dwFlags_ | EWF_BDESTROYWINDOW;

    if (FLAGS_CHECK(pWnd->dwStyle_, EWS_POPUPWINDOW))
    {
        wnd_s *pWndParent;
        if (_handle_validate(pWnd->hExDuiParent_, HT_DUI, (LPVOID *)&pWndParent, &nError))
        {
            FLAGS_DEL(pWndParent->dwFlags_, EWF_BPOPUPWINDOIWSHOWN);
            pWndParent->hWndPopup_ = 0;

            if (_handle_validate(pWnd->lpPopupParams_, HT_OBJECT, (LPVOID *)&pObj, &nError))
            {
                _obj_baseproc(pWndParent->hWnd_, pWnd->lpPopupParams_, pObj, -7, 0, 0);
                IME_Control(pWndParent->hWnd_, pWndParent, FALSE);
            }
        }
        nError = 0;
        pObj = NULL;
    }

    DestroyWindow(pWnd->hWndTips_);
    DestroyWindow(pWnd->hWndShadow_);

    if (_handle_validate(pWnd->objChildFirst_, HT_OBJECT, (LPVOID *)&pObj, &nError))
    {
        _obj_notify_brothers(hWnd, pWnd->objChildFirst_, pObj, WM_DESTROY, 0, 0, FALSE, FALSE);
    }

    //clear MESSAGEBOX
    if (((pWnd->dwStyle_ & EWS_MESSAGEBOX) == EWS_MESSAGEBOX))
    {
        if (pWnd->lpMsgParams_ != 0)
        {
            if (pWnd->lpMsgParams_->lpCheckBox_ != 0)
            {
                size_t dwTmp = 0;
                if (HashTable_Get(pWnd->hTableObjects_, (size_t)(pWnd->lpMsgParams_->lpCheckBoxChecked_), &dwTmp))
                {
                    if (dwTmp != 0)
                    {
                        __set_int(pWnd->lpMsgParams_->lpCheckBoxChecked_, 0, Ex_ObjDispatchMessage(dwTmp, BM_GETCHECK, 0, 0));
                    }
                }
            }
        }
    }

    //clear NotifyIcon
    if (pWnd->lpNid_)
    {
        Shell_NotifyIconW(NIM_DELETE, (PNOTIFYICONDATAW)pWnd->lpNid_);
        Ex_MemFree(pWnd->lpNid_);
        pWnd->lpNid_ = 0;
    }

    //clear DropTarget
    if (pWnd->lpIDropTarget_)
    {
        ((DropTarget *)pWnd->lpIDropTarget_)->Release();
        delete (DropTarget *)pWnd->lpIDropTarget_;
        pWnd->lpIDropTarget_ = nullptr;
    }

    HashTable_Destroy(pWnd->hTableObjects_);
    HashTable_Destroy(pWnd->hTableEvent_);

    //clear bkgimginfo
    KillTimer(hWnd, (size_t)pWnd + TIMER_BKG_INHERIT);
    _obj_backgroundimage_clear(hWnd, (obj_base *)pWnd);

    //clear font
    _font_destroy(pWnd->hFont_Menu_);

    BOOL bMainWnd = ((pWnd->dwStyle_ & EWS_MAINWINDOW) == EWS_MAINWINDOW);
    _struct_destroyfromaddr(pWnd, offsetof(wnd_s, ti_auto_));
    _struct_destroyfromaddr(pWnd, offsetof(wnd_s, ti_track_));
    _rgn_destroy(pWnd->hrgn_client_);
    _rgn_destroy(pWnd->hrgn_sizebox_);
    _canvas_destroy(pWnd->canvas_bkg_);
    _canvas_destroy(pWnd->canvas_display_);

    if (pWnd->hLayout_ != 0)
    {
        _layout_destroy(pWnd->hLayout_);
    }

    _wnd_dx_unint(pWnd);
    HEXDUI hExDui = pWnd->hexdui_;
    nError = 0;
    _handle_destroy(hExDui, &nError);
    Ex_MemFree(pWnd);
    Ex_SetLastError(nError);
    return bMainWnd ? 1 : 0;
}

void _wnd_paint_bkg(HWND hWnd, wnd_s *pWnd)
{
    HEXCANVAS cvBkg = pWnd->canvas_bkg_;
    wnd_s *p = pWnd;
    if (_canvas_begindraw(cvBkg))
    {
        _canvas_setantialias(cvBkg, TRUE);
        _canvas_setimageantialias(cvBkg, TRUE);
        LRESULT result = 0;
        if (!pWnd->pfnMsgProc_ || !pWnd->pfnMsgProc_(hWnd, pWnd->hexdui_, WM_ERASEBKGND, cvBkg, MAKELONG(pWnd->width_, pWnd->height_), &result))
        {
            if (!((pWnd->dwStyle_ & EWS_NOINHERITBKG) == EWS_NOINHERITBKG))
            {
                wnd_s *pParent = nullptr;
                INT nError = 0;
                if (_handle_validate(pWnd->hExDuiParent_, HT_DUI, (LPVOID *)&pParent, &nError))
                {
                    p = pParent;
                }

                if ((pWnd->dwFlags_ & EWF_BINHERITBKGSTARTED) != EWF_BINHERITBKGSTARTED)
                {
                    pWnd->dwFlags_ = pWnd->dwFlags_ | EWF_BINHERITBKGSTARTED;
                    SetTimer(hWnd, (size_t)pWnd + TIMER_BKG_INHERIT, 100, &_wnd_backgroundimage_timer_inherit);

                }
            }
            //绘制底色

            _canvas_clear(cvBkg, p->crBkg_);

            //绘制背景
            if (p->lpBackgroundImage_)
            {
                _canvas_drawimagefrombkgimg(cvBkg, p->lpBackgroundImage_);
            }
        }

        if (pWnd->fBlur_)
        {
            _canvas_blur(cvBkg, pWnd->fBlur_, 0);
        }

        if (((pWnd->dwStyle_ & EWS_MESSAGEBOX) == EWS_MESSAGEBOX))
        {
            _msgbox_drawinfo(pWnd, cvBkg);
        }
        if (FLAGS_CHECK(pWnd->dwStyle_, EWS_COMBOWINDOW))
        {
            Ex_ThemeDrawControl(pWnd->hTheme_, cvBkg, 0, 0, pWnd->width_ - 1, pWnd->height_ - 1, -1741080004, ATOM_NORMAL, 255);
        }
    }
    _canvas_enddraw(cvBkg);
    _obj_compostied_all(pWnd->objChildFirst_);
}

void _wnd_render_dc(HWND hWnd, wnd_s *pWnd, LPVOID hDC, HEXCANVAS cvDisplay, RECT rcPaint, BOOL fLayer)
{
    LPVOID mDC = _canvas_getdc(cvDisplay);
    if (mDC != 0)
    {
        if (fLayer)
        {
            pWnd->ulwi_prcDirty_left_ = rcPaint.left;
            pWnd->ulwi_prcDirty_top_ = rcPaint.top;
            pWnd->ulwi_prcDirty_right_ = rcPaint.right;
            pWnd->ulwi_prcDirty_bottom_ = rcPaint.bottom;

            pWnd->ulwi_.hdcSrc = (HDC)mDC;
            if (g_Li.pfnUpdateLayeredWindowIndirect)
            {
                ((UpdateLayeredWindowIndirectPROC)g_Li.pfnUpdateLayeredWindowIndirect)(hWnd, &pWnd->ulwi_);
            }
            else
            {
                BLENDFUNCTION pb_;
                pb_.BlendOp = 0;
                pb_.BlendFlags = 0;
                pb_.SourceConstantAlpha = 0xFF;
                pb_.AlphaFormat = 1;
                UpdateLayeredWindow(hWnd, 0, 0, (SIZE *)pWnd->ulwi_.psize, pWnd->ulwi_.hdcSrc, (POINT *)pWnd->ulwi_.pptSrc, 0, &pb_, ULW_ALPHA);
            }
        }
        else
        {
            BitBlt((HDC)hDC, rcPaint.left, rcPaint.top, rcPaint.right - rcPaint.left, rcPaint.bottom - rcPaint.top, (HDC)mDC, rcPaint.left, rcPaint.top, SRCCOPY);
        }
        _canvas_releasedc(cvDisplay);
    }
}

void _wnd_render(HWND hWnd, wnd_s *pWnd, LPVOID hDC, RECT rcPaint, BOOL fLayer, BOOL fDX)
{
    pWnd->dwFlags_ = pWnd->dwFlags_ | EWF_BRENDERING;

    if ((pWnd->dwFlags_ & EWF_BREDRAWBACKGROUND) == EWF_BREDRAWBACKGROUND)
    {
        pWnd->dwFlags_ = pWnd->dwFlags_ - (pWnd->dwFlags_ & EWF_BREDRAWBACKGROUND);
        _wnd_paint_bkg(hWnd, pWnd);
    }
    HEXCANVAS cvDisplay = pWnd->canvas_display_;
    if (_canvas_begindraw(cvDisplay))
    {
        ID2D1DeviceContext *pContext = nullptr;
        ID2D1Bitmap *pBitmapDisplay = nullptr;
        if (fDX)
        {
            pContext = pWnd->dx_context_;
            pBitmapDisplay = (ID2D1Bitmap *)_canvas_getcontext(cvDisplay, CVC_DX_D2DBITMAP);
            _dx_bmp_copyfrom(&pBitmapDisplay, (ID2D1Bitmap *)_canvas_getcontext(pWnd->canvas_bkg_, CVC_DX_D2DBITMAP), rcPaint.left, rcPaint.top, rcPaint.left, rcPaint.top, rcPaint.right, rcPaint.bottom);

            _dx_settarget(pContext, (ID2D1Bitmap *)pBitmapDisplay);
        }
        else
        {

            _canvas_bitblt(cvDisplay, pWnd->canvas_bkg_, rcPaint.left, rcPaint.top, rcPaint.right, rcPaint.bottom, rcPaint.left, rcPaint.top);
        }

        LPVOID hBrush = nullptr;
        if (Flag_Query(EXGF_OBJECT_SHOWRECTBORDER))
        {
            hBrush = _brush_create(-65536);
        }
        _wnd_render_obj(hWnd, pWnd, pContext, cvDisplay, pBitmapDisplay, rcPaint, pWnd->objChildFirst_, 0, 0, 255, fDX, hBrush);
        _brush_destroy(hBrush);
        _wnd_render_dc(hWnd, pWnd, hDC, cvDisplay, rcPaint, fLayer);
        _canvas_enddraw(cvDisplay);
    }
    pWnd->dwFlags_ = pWnd->dwFlags_ - (pWnd->dwFlags_ & EWF_BRENDERING);
}

INT _wnd_popupclose(wnd_s *pWnd, HWND hWnd, INT wParam, obj_s *pObj)
{
    INT result = 0;
    INT nError = 0;

    if (FLAGS_CHECK(pWnd->dwFlags_, EWF_BPOPUPWINDOIWSHOWN))
    {
        if (!pObj || (!_handle_validate(pWnd->lpPopupParams_, HT_OBJECT, (LPVOID *)&pObj, &nError)) || (result = _obj_baseproc(hWnd, pObj->hObj_, pObj, -7, wParam, 0)) == 0)
        {
            FLAGS_DEL(pWnd->dwFlags_, EWF_BPOPUPWINDOIWSHOWN);
            result = DestroyWindow(pWnd->hWndPopup_);
        }
    }
    return result;
}

void _wnd_wm_size(wnd_s *pWnd, HWND hWnd, WPARAM wParam, INT width, INT height)
{
    pWnd->dwFlags_ = pWnd->dwFlags_ - (pWnd->dwFlags_ & EWF_BRENDERED);
    pWnd->dwFlags_ = pWnd->dwFlags_ | EWF_SIZED | EWF_BREDRAWBACKGROUND;
    if (width != pWnd->width_ || height != pWnd->height_)
    {

        if (((pWnd->dwStyle_ & EWS_MESSAGEBOX) == EWS_MESSAGEBOX))
        {
            _wnd_addstyle(hWnd, WS_EX_LAYERED, TRUE);
        }

        if (((pWnd->dwStyle_ & EWS_MENU) == EWS_MENU))
        {
            width = width - GetSystemMetrics(SM_CXFIXEDFRAME) * 2;
            height = height - GetSystemMetrics(SM_CYFIXEDFRAME) * 2;
        }
        _wnd_recalcclient(pWnd, hWnd, width, height);
        _layout_update(pWnd->hLayout_);
        RECT rcCaption{0};
        _wnd_calc_captionrect(pWnd, &rcCaption);
        Ex_ObjSetPos(pWnd->objCaption_, 0, 0, 0, rcCaption.right - rcCaption.left, EOP_DEFAULT, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOCOPYBITS | SWP_EX_NODPISCALE);
        if (pWnd->dwWinState_ != wParam)
        {
            if (((pWnd->dwStyle_ & EWS_BUTTON_MAX) == EWS_BUTTON_MAX))
            {
                Ex_ObjInvalidateRect(_obj_getobjfromidorname(pWnd, EWS_BUTTON_MAX), 0);
            }

            if (((pWnd->dwStyle_ & EWS_BUTTON_MIN) == EWS_BUTTON_MIN))
            {
                Ex_ObjInvalidateRect(_obj_getobjfromidorname(pWnd, EWS_BUTTON_MIN), 0);
            }
            pWnd->dwWinState_ = wParam;
        }
    }
    InvalidateRect(hWnd, 0, FALSE);
}

void _wnd_menu_setpos(HWND hWnd, wnd_s *pWnd, tagWINDOWPOS *pos)
{
    wnd_s *pMenuHostWnd = pWnd->pMenuHostWnd_;
    wnd_s *pMenuPrevWnd = nullptr;
    RECT rcParent{0};
    if (pMenuHostWnd != 0)
    {
        pMenuPrevWnd = pMenuHostWnd->pMenuPrevWnd_;
        if (pMenuPrevWnd != 0)
        {
            GetWindowRect(pMenuPrevWnd->hWnd_, &rcParent);
        }
    }
    auto offset = LOBYTE(HIWORD(pWnd->szItemSeparator_));
    INT x = pos->x;
    INT y = pos->y;
    POINT pt;
    GetCursorPos(&pt);
    if (rcParent.left < x) //子菜单在右边
    {
        x = rcParent.right + offset - 1;
    }
    else
    {
        //子菜单在左边
        x = rcParent.left;
        GetWindowRect(hWnd, &rcParent);
        x = x - (rcParent.right - rcParent.left) + GetSystemMetrics(SM_CXFIXEDFRAME) * 2 + 1;
        x = x - offset;
    }
    pos->x = x;
    if (pMenuPrevWnd != 0)
    {
        HEXOBJ hObj = pMenuPrevWnd->objFocus_;
        obj_s *pObj = nullptr;
        INT nError = 0;
        if (_handle_validate(hObj, HT_OBJECT, (LPVOID *)&pObj, &nError))
        {
            LPVOID padding_client = pWnd->padding_client_;
            y = pObj->w_top_ + pMenuPrevWnd->top_ - __get_int(padding_client, 4);
            GetWindowRect(hWnd, &rcParent);
            INT height = rcParent.bottom - rcParent.top - GetSystemMetrics(SM_CYFIXEDFRAME) * 2;
            _wnd_getscreenrect(hWnd, &rcParent);
            
            if (y + height > rcParent.bottom)
            {
                y = pObj->w_bottom_ - height + __get_int(padding_client, 12);
                
            }
        }
    }
    pos->y = y;
}

void _wnd_menu_createitems(HWND hWnd, wnd_s *pWnd)
{
    size_t hMenu = SendMessageW(hWnd, MN_GETHMENU, 0, 0);
    HEXTHEME hTheme = pWnd->hTheme_;
    LPVOID lpPaddingText = Ex_ThemeGetValuePtr(hTheme, ATOM_DUIMENU, ATOM_PADDING_TEXT);
    INT nCount = GetMenuItemCount((HMENU)hMenu);
    wnd_s *pMenuHostWnd = pWnd->pMenuHostWnd_;
    HWND hParent = pMenuHostWnd->hWnd_;
    RECT rcParent{0};
    GetWindowRect(hParent, &rcParent);
    LPVOID padding_client = pWnd->padding_client_;
    RECT rcPaddingClient = {0};
    if (padding_client != 0)
    {
        RtlMoveMemory(&rcPaddingClient, padding_client, 16);
        if (g_Li.DpiX > 1)
        {
            rcPaddingClient.left = rcPaddingClient.left * g_Li.DpiX;
            rcPaddingClient.top = rcPaddingClient.top * g_Li.DpiX;
            rcPaddingClient.right = rcPaddingClient.right * g_Li.DpiX;
            rcPaddingClient.bottom = rcPaddingClient.bottom * g_Li.DpiX;
        }
    }

    obj_s *pParnet = nullptr;
    INT nError = 0;
    HEXOBJ objParent = _obj_create_init(hWnd, pWnd, ATOM_PAGE, 0, &pParnet, &nError);
    if (objParent != 0)
    {
        INT width = pWnd->width_ - (rcPaddingClient.left + rcPaddingClient.right);
        INT height = pWnd->height_ - (rcPaddingClient.top + rcPaddingClient.bottom);
        _obj_create_proc(&nError, FALSE, hTheme, pParnet, EOS_EX_FOCUSABLE, ATOM_PAGE, 0, EOS_VISIBLE | EOS_VSCROLL | EMIS_SUBMENU, rcPaddingClient.left, rcPaddingClient.top, width, height, 0, 0, 0, 0, 0);
        _obj_create_done(hWnd, pWnd, objParent, pParnet);
        HEXOBJ objPP = objParent;
        HEXLAYOUT hLayout = _layout_create(ELT_ABSOLUTE, pWnd->hexdui_);
        _layout_absolute_setedge(hLayout, objPP, ELCP_ABSOLUTE_LEFT, ELCP_ABSOLUTE_TYPE_PX, rcPaddingClient.left);
        _layout_absolute_setedge(hLayout, objPP, ELCP_ABSOLUTE_TOP, ELCP_ABSOLUTE_TYPE_PX, rcPaddingClient.top);
        _layout_absolute_setedge(hLayout, objPP, ELCP_ABSOLUTE_RIGHT, ELCP_ABSOLUTE_TYPE_PX, rcPaddingClient.right);
        _layout_absolute_setedge(hLayout, objPP, ELCP_ABSOLUTE_BOTTOM, ELCP_ABSOLUTE_TYPE_PX, rcPaddingClient.bottom);
        nError = 0;
        objParent = _obj_create_init(hWnd, pWnd, ATOM_PAGE, 0, &pParnet, &nError);
        if (objParent != 0)
        {
            INT heightParent = height;
            _obj_create_proc(&nError, FALSE, hTheme, pParnet, EOS_EX_FOCUSABLE, ATOM_PAGE, 0, EOS_VISIBLE, 0, 0, width, height, objPP, 0, 0, 0, 0);
            _obj_create_done(hWnd, pWnd, objParent, pParnet);
            hLayout = _layout_create(ELT_ABSOLUTE, objPP);
            _layout_absolute_setedge(hLayout, objParent, ELCP_ABSOLUTE_LEFT, ELCP_ABSOLUTE_TYPE_PX, 0);
            _layout_absolute_setedge(hLayout, objParent, ELCP_ABSOLUTE_TOP, ELCP_ABSOLUTE_TYPE_PX, 0);
            _layout_absolute_setedge(hLayout, objParent, ELCP_ABSOLUTE_RIGHT, ELCP_ABSOLUTE_TYPE_PX, 0);
            _layout_absolute_setedge(hLayout, objParent, ELCP_ABSOLUTE_BOTTOM, ELCP_ABSOLUTE_TYPE_PX, 0);
            height = 0;
            MENUITEMINFOW mii;
            mii.cbSize = sizeof(MENUITEMINFOW);
            mii.fMask = MIIM_FTYPE | MIIM_SUBMENU | MIIM_ID;
            RECT rcItem{0};
            INT eos;
            INT offsetTop = 0;
            for (INT i = 0; i < nCount; i++)
            {
                if (GetMenuItemRect(hParent, (HMENU)hMenu, i, &rcItem))
                {
                    eos = EOS_VISIBLE;
                    if (GetMenuItemInfoW((HMENU)hMenu, i, TRUE, &mii))
                    {
                        if ((mii.fType & MFT_SEPARATOR) != 0) //分隔符
                        {
                            eos = eos | EMIS_SEPARATOR;
                        }
                        else
                        {
                            if (mii.hSubMenu != 0)
                            {
                                eos = eos | EMIS_SUBMENU;
                            }
                        }
                    }
                    WCHAR buff[520];
                    OffsetRect(&rcItem, -rcParent.left, -rcParent.top);
                    // 组件超出屏幕左边会出现菜单项目左边负数
                    if (rcItem.left < 0)
                    {
                        INT offset = abs(rcItem.left);
                        rcItem.left = rcItem.left + offset;
                        rcItem.right = rcItem.right + offset;
                    }
                    else if (rcItem.left > 0)
                    {
                        INT offset = abs(rcItem.left);
                        rcItem.left = rcItem.left - offset;
                        rcItem.right = rcItem.right - offset;
                    }
                    // 判断第一项，取第一项顶边偏移,组件移到屏幕最顶端二级子菜单第一项会负数
                    if (rcItem.top < 0 && i == 0)
                    {
                        offsetTop = abs(rcItem.top);
                    }
                    rcItem.top = rcItem.top + offsetTop;
                    rcItem.bottom = rcItem.bottom + offsetTop;
                    GetMenuStringW((HMENU)hMenu, i, buff, 520, MF_BYPOSITION);
                    obj_s *pObj = nullptr;
                    nError = 0;
                    HEXOBJ hObj = _obj_create_init(hWnd, pWnd, ATOM_ITEM, 0, &pObj, &nError);
                    if (hObj != 0)
                    {
                        _obj_create_proc(&nError, FALSE, hTheme, pObj, EOS_EX_FOCUSABLE | EOS_EX_TABSTOP, ATOM_ITEM, buff, eos, rcItem.left, rcItem.top, width, rcItem.bottom - rcItem.top, objParent, mii.wID, 0, i, DT_VCENTER | DT_SINGLELINE);
                        pObj->dwFlags_ = pObj->dwFlags_ | EOF_BMENUITEM;
                        _obj_create_done(hWnd, pWnd, hObj, pObj);
                        if (lpPaddingText != 0)
                        {
                            RtlMoveMemory((LPVOID)((size_t)pObj + offsetof(obj_s, t_left_)), lpPaddingText, 16);
                            if (g_Li.DpiX > 1)
                            {
                                pObj->t_left_ = pObj->t_left_ * g_Li.DpiX;
                                pObj->t_top_ = pObj->t_top_ * g_Li.DpiY;
                                pObj->t_right_ = pObj->t_right_ * g_Li.DpiX;
                                pObj->t_bottom_ = pObj->t_bottom_ * g_Li.DpiY;
                            }
                        }
                    }
                    height = height + rcItem.bottom - rcItem.top;
                }
            }
            _obj_setpos_org(pParnet, objParent, 0, EOP_DEFAULT, EOP_DEFAULT, EOP_DEFAULT, height, SWP_NOMOVE | SWP_NOZORDER | SWP_NOREDRAW | SWP_NOACTIVATE | SWP_NOCOPYBITS | SWP_EX_NODPISCALE, 0);
            height = height - 1;
            Ex_ObjScrollShow(objPP, SB_VERT, height - heightParent > 0);
            Ex_ObjScrollSetInfo(objPP, SB_VERT, SIF_RANGE | SIF_PAGE, 0, height - heightParent, heightParent, 0, TRUE);
        }
    }
    SendMessageW(hWnd, WM_INITMENUPOPUP, hMenu, 0);
}

void _wnd_menu_init(HWND hWnd, wnd_s *pWnd)
{

    if ((pWnd->dwFlags_ & EWF_BMENUINITED) != EWF_BMENUINITED)
    {
        pWnd->dwFlags_ = pWnd->dwFlags_ | EWF_BMENUINITED;
        _wnd_menu_createitems(hWnd, pWnd);
        ShowWindow(pWnd->hWndShadow_, SW_SHOWNOACTIVATE);

        SetWindowLongPtrW(hWnd, GWL_STYLE, WS_POPUP | WS_VISIBLE);
        InvalidateRect(hWnd, NULL, FALSE);
    }
}

void _wnd_paint_shadow(wnd_s *pWnd, BOOL bUpdateRgn, BOOL bFlush)
{

    if (!((pWnd->dwStyle_ & EWS_NOSHADOW) == EWS_NOSHADOW))
    {

        if ((pWnd->dwFlags_ & EWF_BRENDERED) == EWF_BRENDERED)
        {
            HWND hWnd = pWnd->hWndShadow_;
            POINT ptDst;
            ptDst.x = pWnd->left_;
            ptDst.y = pWnd->top_;
            SIZE sz;
            sz.cx = pWnd->width_;
            sz.cy = pWnd->height_;
            LPVOID prcPadding = pWnd->padding_shadow_;
            RECT rcPadding{0};
            if (prcPadding != 0)
            {
                RtlMoveMemory(&rcPadding, prcPadding, sizeof(RECT));
                ptDst.x = ptDst.x - rcPadding.left;
                ptDst.y = ptDst.y - rcPadding.top;
                sz.cx = sz.cx + rcPadding.left + rcPadding.right;
                sz.cy = sz.cy + rcPadding.top + rcPadding.bottom;
            }
            MoveWindow(hWnd, ptDst.x, ptDst.y, sz.cx, sz.cy, FALSE);
            if (bUpdateRgn || bFlush)
            {
                auto hDC = GetDC(hWnd);
                if (hDC != 0)
                {
                    INT nError = 0;
                    HEXCANVAS cvShadow = _canvas_createfrompwnd(pWnd, sz.cx, sz.cy, ECVF_GDI_COMPATIBLE, &nError);
                    if (cvShadow != 0)
                    {
                        INT alpha = ((pWnd->dwFlags_ & EWF_ACTIVE) == EWF_ACTIVE) ? 255 : 204;
                        alpha = alpha * pWnd->alpha_ / 255;
                        if (_canvas_begindraw(cvShadow))
                        {
                            _canvas_setantialias(cvShadow, TRUE);
                            _canvas_setimageantialias(cvShadow, TRUE);
                            _canvas_drawshadow(cvShadow,11,11,sz.cx-11,sz.cy-11,11,pWnd->crSD_,pWnd->Radius_,pWnd->Radius_,pWnd->Radius_,pWnd->Radius_,0,0);
                            LPVOID mDC = _canvas_getdc(cvShadow);
                            if (mDC != 0)
                            {
                                POINT ptSrc = {0};
                                BLENDFUNCTION pb_;
                                pb_.BlendOp = 0;
                                pb_.BlendFlags = 0;
                                pb_.SourceConstantAlpha = 0xFF;
                                pb_.AlphaFormat = 1;
                                UpdateLayeredWindow(hWnd, hDC, &ptDst, &sz, (HDC)mDC, &ptSrc, 0, &pb_, ULW_ALPHA);
                                _canvas_releasedc(cvShadow);
                            }
                            _canvas_enddraw(cvShadow);
                        }
                        _canvas_destroy(cvShadow);
                    }
                    ReleaseDC(hWnd, hDC);
                }
            }
        }
    }
}

BOOL _wnd_wm_paint(wnd_s *pWnd, HWND hWnd)
{
    PAINTSTRUCT ps = {0};

    if (((pWnd->dwFlags_ & EWF_INTED) == EWF_INTED))
    {

        BOOL fSized = ((pWnd->dwFlags_ & EWF_SIZED) == EWF_SIZED);
        if (fSized)
        {
            pWnd->dwFlags_ = pWnd->dwFlags_ - (pWnd->dwFlags_ & EWF_SIZED);
        }

        BOOL fLayer = ((pWnd->dwFlags_ & EWF_BLAYERED) == EWF_BLAYERED);

        if (fLayer)
        {
            if (fSized)
            {
                ps.rcPaint.right = pWnd->width_;
                ps.rcPaint.bottom = pWnd->height_;
            }
            else
            {
                GetUpdateRect(hWnd, &ps.rcPaint, FALSE);

                if (((pWnd->dwStyle_ & EWS_MENU) == EWS_MENU))
                {
                }
            }
        }
        else
        {
            BeginPaint(hWnd, &ps);
        }

        _wnd_render(hWnd, pWnd, ps.hdc, ps.rcPaint, fLayer, TRUE);
        if (!fLayer)
        {
            EndPaint(hWnd, &ps);
        }
    }
    if ((pWnd->dwFlags_ & EWF_BRENDERED) != EWF_BRENDERED)
    {
        pWnd->dwFlags_ = pWnd->dwFlags_ | EWF_BRENDERED;
        _wnd_paint_shadow(pWnd, TRUE, FALSE);
    }
    return FALSE;
}

BOOL _wnd_wm_getminmaxinfo(wnd_s *pWnd, HWND hWnd, LPARAM lParam)
{
    RECT rcMonitor{0}, rcDesk{0};
    BOOL ret = FALSE;
    if (_wnd_getscreenrect(hWnd, &rcMonitor, &rcDesk))
    {
        INT width = pWnd->width_;
        INT height = pWnd->height_;

        if (((pWnd->dwStyle_ & EWS_FULLSCREEN) == EWS_FULLSCREEN)) //全屏模式
        {
            RtlMoveMemory(&rcDesk, &rcMonitor, 16);
        }

        OffsetRect(&rcDesk, -rcMonitor.left, -rcMonitor.top);

        //左边，顶边
        ((MINMAXINFO*)lParam)->ptMaxPosition.x = rcDesk.left - 1;
        ((MINMAXINFO*)lParam)->ptMaxPosition.y = rcDesk.top - 1;

        //最大宽度，高度
        INT nMaxWidth = rcDesk.right - rcDesk.left + 2;
        INT nMaxHeight = rcDesk.bottom - rcDesk.top + 2;
        ((MINMAXINFO*)lParam)->ptMaxSize.x = nMaxWidth;
        ((MINMAXINFO*)lParam)->ptMaxSize.y = nMaxHeight;

        //允许调整的最小尺寸
        ((MINMAXINFO*)lParam)->ptMinTrackSize.x = pWnd->minWidth_;
        ((MINMAXINFO*)lParam)->ptMinTrackSize.y = pWnd->minHeight_;

        //允许调整的最大尺寸
        ((MINMAXINFO*)lParam)->ptMaxTrackSize.x = nMaxWidth;
        ((MINMAXINFO*)lParam)->ptMaxTrackSize.y = nMaxHeight;
        ret = TRUE;
    }
    return ret;
}

void _wnd_wm_buttondown(HWND hWnd, wnd_s *pWnd, HEXOBJ hObj, obj_s *pObj, INT uMsg, WPARAM wParam, LPARAM lParam)
{
    if ((pWnd->dwFlags_ & EWF_BTRACKOBJECT) != EWF_BTRACKOBJECT)
    {
        pWnd->dwFlags_ = pWnd->dwFlags_ - (pWnd->dwFlags_ & (EWF_BLEFTTRACK | EWF_BRIGHTTRACK | EWF_BMIDTRACK | EWF_BLEFTDTRACK));
        pWnd->dwFlags_ = pWnd->dwFlags_ | EWF_BTRACKOBJECT;
        if (uMsg == WM_LBUTTONDOWN)
        {
            pWnd->dwFlags_ = pWnd->dwFlags_ | EWF_BLEFTTRACK;
            _obj_setfocus(hWnd, pWnd, hObj, pObj, TRUE);
        }
        else if (uMsg == WM_LBUTTONDBLCLK)
        {
            pWnd->dwFlags_ = pWnd->dwFlags_ | EWF_BLEFTDTRACK;
            _obj_setfocus(hWnd, pWnd, hObj, pObj, TRUE);
			uMsg = WM_LBUTTONDOWN;
        }
        else if (uMsg == WM_RBUTTONDOWN)
        {
            pWnd->dwFlags_ = pWnd->dwFlags_ | EWF_BRIGHTTRACK;
        }
        else
        {
            pWnd->dwFlags_ = pWnd->dwFlags_ | EWF_BMIDTRACK;
        }
        pWnd->objTrack_ = hObj;
        _obj_tooltips_popup(pWnd, 0, 0, -1, -1, -1, 0, FALSE);
        _obj_baseproc(hWnd, hObj, pObj, uMsg, wParam, lParam);
        if (wParam != 0)
        {
            SetCapture(hWnd); //对menu窗口无效
        }
    }
}

void _wnd_obj_untrack(HWND hWnd, wnd_s *pWnd, LPARAM lParam, BOOL fMsgDispatch)
{

    if (((pWnd->dwFlags_ & EWF_BTRACKOBJECT) == EWF_BTRACKOBJECT))
    {
        pWnd->dwFlags_ = pWnd->dwFlags_ - (pWnd->dwFlags_ & EWF_BTRACKOBJECT);
        HEXOBJ objTrack = pWnd->objTrack_;
        pWnd->objTrack_ = 0;
        pWnd->objTrackPrev_ = objTrack;
        if (!fMsgDispatch)
        {
            ReleaseCapture(); //对menu窗口无效
        }
        obj_s *pObj = nullptr;
        INT nError = 0;
        if (_handle_validate(objTrack, HT_OBJECT, (LPVOID *)&pObj, &nError))
        {
            POINT pt;
            GetCursorPos(&pt);
            INT uMsg;
            if (fMsgDispatch)
            {

                if ((pWnd->dwFlags_ & EWF_BLEFTTRACK) == EWF_BLEFTTRACK)
                {
                    uMsg = WM_LBUTTONUP;
                }
                else if ((pWnd->dwFlags_ & EWF_BRIGHTTRACK) == EWF_BRIGHTTRACK)
                {
                    uMsg = WM_RBUTTONUP;
                }
                else if ((pWnd->dwFlags_ & EWF_BMIDTRACK) == EWF_BMIDTRACK)
                {
                    uMsg = WM_MBUTTONUP;
                }
                _obj_baseproc(hWnd, objTrack, pObj, uMsg, 0, 0);

                _wnd_wm_nchittest(pWnd, hWnd, MAKELONG(pt.x, pt.y));
                obj_s Obj;
                _wnd_wm_leavecheck(hWnd, pWnd, objTrack, -1, &Obj, lParam, FALSE);
            }
            else
            {
                _wnd_wm_nchittest(pWnd, hWnd, MAKELONG(pt.x, pt.y));
                obj_s Obj;
                _wnd_wm_leavecheck(hWnd, pWnd, objTrack, -1, &Obj, lParam, FALSE);
                if (pWnd->objHittest_ == objTrack)
                {
                    if (((pWnd->dwFlags_ & EWF_BLEFTTRACK) == EWF_BLEFTTRACK))
                    {
                        uMsg = WM_EX_LCLICK;
                    }
                    else if (((pWnd->dwFlags_ & EWF_BLEFTDTRACK) == EWF_BLEFTDTRACK))
                    {
                        uMsg = WM_EX_LDCLICK;
                    }
                    else if (((pWnd->dwFlags_ & EWF_BRIGHTTRACK) == EWF_BRIGHTTRACK))
                    {
                        uMsg = WM_EX_RCLICK;
                    }
                    else
                    {
                        uMsg = WM_EX_MCLICK;
                    }
                    _obj_baseproc(hWnd, objTrack, pObj, uMsg, 0, pWnd->dwHitObjPos_Abs_);
                }
            }
            _obj_dispatchnotify(hWnd, pObj, objTrack, 0, NM_RELEASEDCAPTURE, 0, 0);
        }
    }
}

void _wnd_wm_captionchange(HWND hWnd, wnd_s *pWnd, LPARAM lParam)
{
    _wnd_obj_untrack(hWnd, pWnd, lParam, FALSE);
}

void _wnd_wm_mouse(wnd_s *pWnd, HWND hWnd, INT uMsg, WPARAM wParam, LPARAM lParam)
{
    HEXOBJ hObj;
    LPARAM OldlParam = lParam;
    if (((pWnd->dwFlags_ & EWF_BTRACKOBJECT) == EWF_BTRACKOBJECT)) //是否按住组件
    {
        hObj = pWnd->objTrack_;
    }
    else
    {
        hObj = pWnd->objHittest_;
    }
    INT dwHitCode = pWnd->dwHitCode_;
    obj_s *pObj = nullptr;
    INT nError = 0;
    if (_handle_validate(hObj, HT_OBJECT, (LPVOID *)&pObj, &nError))
    {

        if (((pWnd->dwFlags_ & EWF_BTRACKOBJECT) == EWF_BTRACKOBJECT))
        {
            lParam = MAKELONG(GET_X_LPARAM(lParam) - pObj->w_left_, GET_Y_LPARAM(lParam) - pObj->w_top_);
            pWnd->dwHitObjPos_Abs_ = lParam;
        }
        else
        {
            lParam = pWnd->dwHitObjPos_Abs_;
        }
    }
    if (uMsg == WM_MOUSEMOVE)
    {
        if (wParam == 0)
        {
            _wnd_wm_leavecheck(hWnd, pWnd, pWnd->objHittestPrev_, hObj, pObj, OldlParam, TRUE);
        }
        if (hObj != 0)
        {
            _obj_baseproc(hWnd, hObj, pObj, uMsg, wParam, lParam);
        }
    }
    else
    {

        if (pObj != 0)
        {
            if (uMsg == WM_LBUTTONDOWN)
            {
                _wnd_popupclose(pWnd, hWnd, hObj, pObj);
            }
            if (uMsg == WM_LBUTTONDOWN || uMsg == WM_RBUTTONDOWN || uMsg == WM_MBUTTONDOWN)
            {
                _wnd_wm_buttondown(hWnd, pWnd, hObj, pObj, uMsg, wParam, lParam);
            }
            else if (uMsg == WM_LBUTTONUP || uMsg == WM_RBUTTONUP || uMsg == WM_MBUTTONUP)
            {
                _obj_baseproc(hWnd, hObj, pObj, uMsg, wParam, lParam);
                _wnd_obj_untrack(hWnd, pWnd, lParam, FALSE);
            }
            else if (uMsg == WM_LBUTTONDBLCLK || uMsg == WM_RBUTTONDBLCLK || uMsg == WM_MBUTTONDBLCLK)
            {
                _obj_baseproc(hWnd, hObj, pObj, uMsg, wParam, lParam);
                INT newMsg = uMsg;
                if (uMsg == WM_LBUTTONDBLCLK)
                {
                    newMsg = WM_LBUTTONDBLCLK;
                }
                else if (uMsg == WM_RBUTTONDBLCLK)
                {
                    newMsg = WM_RBUTTONDOWN;
                }
                else
                {
                    newMsg = WM_MBUTTONDOWN;
                }
                _wnd_wm_buttondown(hWnd, pWnd, hObj, pObj, newMsg, wParam, lParam);
            }
        }
    }
}

void _wnd_wm_menucontext(HWND hWnd, wnd_s *pWnd, INT uMsg, WPARAM wParam, LPARAM lParam)
{
    HEXOBJ objHittest = pWnd->objHittest_;
    obj_s *pObj = nullptr;
    INT nError = 0;
    if (_handle_validate(objHittest, HT_OBJECT, (LPVOID *)&pObj, &nError))
    {
        pWnd->objMenucontext_ = objHittest;
        pWnd->dwFlags_ = pWnd->dwFlags_ | EWF_BMENUCONTEXT;
        _obj_baseproc(hWnd, objHittest, pObj, uMsg, wParam, lParam);
        pWnd->dwFlags_ = pWnd->dwFlags_ - (pWnd->dwFlags_ & EWF_BMENUCONTEXT);
    }
}

void _wnd_wm_mousewheel(HWND hWnd, wnd_s *pWnd, INT uMsg, WPARAM wParam, LPARAM lParam)
{
    HEXOBJ objHittest = pWnd->objHittest_;
    obj_s *pObj = nullptr;
    INT nError = 0;

    if (FLAGS_CHECK(pWnd->dwFlags_, EWF_BPOPUPWINDOIWSHOWN))
    {
        hWnd = pWnd->hWndPopup_;
        SendMessage(hWnd, uMsg, wParam, lParam);
        return;
    }

    if (_handle_validate(objHittest, HT_OBJECT, (LPVOID *)&pObj, &nError))
    {
        if (_obj_baseproc(hWnd, objHittest, pObj, uMsg, wParam, lParam) == 0) //我认为这样是不完善的，因为存在转发WHEEL消息让别的控件滚动的可能性
        {
            EX_CLASSINFO *pCls = pObj->pCls_;
            if (pCls->atomName == ATOM_SCROLLBAR)
            {
                _scrollbar_parentnotify(hWnd, pObj, wParam > 0 ? SB_LINEUP : SB_LINEDOWN, objHittest, 0, TRUE);
            }

            if (((pObj->dwStyle_ & EOS_VSCROLL) == EOS_VSCROLL))
            {
                _obj_baseproc(hWnd, objHittest, pObj, WM_VSCROLL, wParam > 0 ? SB_LINEUP : SB_LINEDOWN, 0);
            }

            if (((pObj->dwStyle_ & EOS_HSCROLL) == EOS_HSCROLL))
            {
                _obj_baseproc(hWnd, objHittest, pObj, WM_HSCROLL, wParam > 0 ? SB_LINEUP : SB_LINEDOWN, 0);
            }
        }
    }
}

void _wnd_wm_command(HWND hWnd, wnd_s *pWnd, INT uMsg, WPARAM wParam, LPARAM lParam)
{
    if (((pWnd->dwFlags_ & EWF_BMODAL) == EWF_BMODAL))
    {
        if (wParam == 2)
        {
            if (Ex_ObjIsEnable(Ex_ObjGetFromID(pWnd->objCaption_, EWS_BUTTON_CLOSE))) //判断按下关闭按钮,退出模态窗口
            {
                EndDialog(hWnd, IDCANCEL);
            }
        }
    }
    else
    {
        HEXOBJ objMenucontext = pWnd->objMenucontext_;
        pWnd->objMenucontext_ = 0;
        obj_s *pObj = nullptr;
        INT nError = 0;

        if (_handle_validate(objMenucontext, HT_OBJECT, (LPVOID *)&pObj, &nError))
        {
            _obj_baseproc(hWnd, objMenucontext, pObj, uMsg, wParam, lParam);
        }
    }
}

HEXOBJ _wnd_obj_setnextfocus(HWND hWnd, wnd_s *pWnd, HEXOBJ objEntry, HEXOBJ objLastFocus)
{
    obj_s *pObjEntry = nullptr;
    INT nError = 0;
    while (_handle_validate(objEntry, HT_OBJECT, (LPVOID *)&pObjEntry, &nError))
    {

        if (((pObjEntry->dwStyleEx_ & EOS_EX_TABSTOP) == EOS_EX_TABSTOP))
        {
            if (objLastFocus != objEntry)
            {
                _obj_setfocus(hWnd, pWnd, objEntry, pObjEntry, TRUE);
            }
            return objEntry;
        }
        objEntry = pObjEntry->objNext_;
    }
    return 0;
}

void _wnd_obj_settabstop(HWND hWnd, wnd_s *pWnd, HEXOBJ objLastFocus)
{
    obj_s *pObjLast = nullptr;
    INT nError = 0;
    HEXOBJ objNextFocus;
    if (_handle_validate(objLastFocus, HT_OBJECT, (LPVOID *)&pObjLast, &nError))
    {
        HEXOBJ objNextFocus = _wnd_obj_setnextfocus(hWnd, pWnd, pObjLast->objNext_, objLastFocus);
        if (objNextFocus == 0)
        {
            EXHANDLE objParent = pObjLast->objParent_;
            obj_s *pObjParent = nullptr;
            if (_handle_validate(objParent, HT_OBJECT, (LPVOID *)&pObjParent, &nError))
            {
                objNextFocus = _wnd_obj_setnextfocus(hWnd, pWnd, pObjParent->objChildFirst_, objLastFocus);
            }
            else
            {
                objNextFocus = _wnd_obj_setnextfocus(hWnd, pWnd, pWnd->objChildFirst_, objLastFocus);
            }
        }
    }
    else
    {
        objNextFocus = _wnd_obj_setnextfocus(hWnd, pWnd, pWnd->objChildFirst_, objLastFocus);
    }
}

BOOL _wnd_wm_keyboard(wnd_s *pWnd, HWND hWnd, INT uMsg, WPARAM wParam, LPARAM lParam)
{
    HEXOBJ objFocus = pWnd->objFocus_;
    obj_s *pObj = nullptr;
    INT nError = 0;
    BOOL bPopupWindowShown = FALSE;
    if (_handle_validate(objFocus, HT_OBJECT, (LPVOID *)&pObj, &nError) && uMsg != WM_IME_CHAR)
    {
        if (FLAGS_CHECK(pWnd->dwFlags_, EWF_BPOPUPWINDOIWSHOWN))
        {

            if (uMsg >= WM_KEYDOWN && uMsg <= WM_KEYLAST)
            {
                SendMessageW(pWnd->hWndPopup_, uMsg, wParam, lParam);
                bPopupWindowShown = TRUE;
            }
        }
        if (_obj_baseproc(hWnd, objFocus, pObj, uMsg, wParam, lParam) != 0) //先给组件，看他需不需要消息。
        {
            return 1;
        }
    }
    if (uMsg == WM_KEYDOWN)
    {
        if (wParam == VK_ESCAPE)
        {
            if (((pWnd->dwStyle_ & EWS_ESCEXIT) == EWS_ESCEXIT) && !bPopupWindowShown)
            {
                PostMessageW(hWnd, WM_CLOSE, 0, 0);
            }
        }
        else if (wParam == VK_SPACE)
        {
            if (_wnd_getfunctionkeys() == 0)
            {
                if (pObj != 0)
                {
                    if (!__query(pObj, offsetof(obj_s, dwFlags_), EOF_BDISABLESPACEANDENTER))
                    {
                        _wnd_wm_buttondown(hWnd, pWnd, objFocus, pObj, WM_LBUTTONDOWN, 0, 0);
                    }
                }
            }
        }
        else if (wParam == VK_RETURN)
        {
            if (_wnd_getfunctionkeys() == 0)
            {
                if (pObj != 0)
                {
                    if (!__query(pObj, offsetof(obj_s, dwFlags_), EOF_BDISABLESPACEANDENTER))
                    {
                        if (_obj_dispatchnotify(hWnd, pObj, objFocus, 0, NM_RETURN, wParam, lParam) == 0)
                        {
                            _obj_baseproc(hWnd, objFocus, pObj, WM_EX_LCLICK, 0, 0);
                        }
                    }
                }
            }
        }
        else if (wParam == VK_TAB)
        {
            _wnd_obj_settabstop(hWnd, pWnd, objFocus);
        }
        else if (wParam == VK_UP || wParam == VK_DOWN)
        {
            if ((pWnd->dwStyle_ & EWS_MENU) == EWS_MENU)
            {
                return 1;
            }
        }
        else if (wParam == VK_LEFT || wParam == VK_RIGHT)
        {
            if ((pWnd->dwStyle_ & EWS_MENU) == EWS_MENU)
            {
                return 1;
            }
        }

        if ((pWnd->dwFlags_ & EWF_BMODAL) == EWF_BMODAL)
        {
            UINT retvalue = MapVirtualKeyW(wParam, 2); //判断是否不是输入法
            if (retvalue)
            {
                BYTE bs[256] = {0};
                GetKeyboardState(bs);
                WCHAR charactersPressed[2] = {};
                ToUnicode(wParam, lParam, bs, charactersPressed, 2, 0);
                if (pObj != 0)
                {
                    _obj_baseproc(hWnd, objFocus, pObj, WM_CHAR, (WPARAM)charactersPressed[0], lParam);
                }
            }
        }
    }
    else if (uMsg == WM_KEYUP)
    {
        if (wParam == VK_SPACE)
        {
            if (pObj != 0)
            {
                if (!__query(pObj, offsetof(obj_s, dwFlags_), EOF_BDISABLESPACEANDENTER))
                {
                    _wnd_wm_mouse(pWnd, hWnd, WM_LBUTTONUP, 0, 0);
                    _obj_baseproc(hWnd, objFocus, pObj, WM_EX_LCLICK, 0, 0);
                }
            }
        }
    }
    else if (uMsg == WM_COPY)
    {
        if ((pWnd->dwStyle_ & EWS_MESSAGEBOX) == EWS_MESSAGEBOX && pObj)
        {
            if (pObj->pCls_->atomName == ATOM_EDIT)
            {
                return 1;
            }
        }
    }
    else if (uMsg == WM_IME_CHAR)
    {
        if ((pWnd->dwFlags_ & EWF_BMODAL) == EWF_BMODAL && pObj)
        {
            _obj_baseproc(hWnd, objFocus, pObj, WM_CHAR, wParam, lParam);
        }
    }
    return 0;
}

BOOL _wnd_obj_childtabstop(HEXOBJ objEntry, HEXOBJ *objFocusable, LPVOID *pObjFocusable, HEXOBJ objLast, BOOL *bFounded)
{
    obj_s *pObj = nullptr;
    INT nError = 0;
    BOOL ret = FALSE;
    while (_handle_validate(objEntry, HT_OBJECT, (LPVOID *)&pObj, &nError))
    {
        if (!*bFounded)
        {
            if (objLast = objEntry)
                *bFounded = TRUE;
        }

        if (((pObj->dwStyleEx_ & EOS_EX_TABSTOP) == EOS_EX_TABSTOP))
        {
            *objFocusable = objEntry;
            *pObjFocusable = pObj;
            ret = TRUE;
            break;
        }
        HEXOBJ objSub = pObj->objChildFirst_;
        if (objSub != 0)
        {
            if (_wnd_obj_childtabstop(objSub, objFocusable, pObjFocusable, objLast, bFounded))
            {
                ret = TRUE;
                break;
            }
        }
        objEntry = pObj->objNext_;
    }
    return ret;
}

void _wnd_wm_ime_composition(HWND hWnd, wnd_s *pWnd)
{
    auto hImc = ImmGetContext(hWnd);
    if (hImc != 0)
    {
        POINT pt;
        GetCaretPos(&pt);
        if (FLAGS_CHECK(pWnd->dwFlags_, EWF_BPOPUPWINDOIWSHOWN))
        {
            RECT rect;
            GetWindowRect(pWnd->hWndPopup_, &rect);
            pt.x += rect.left - pWnd->left_;
            pt.y += rect.top - pWnd->top_;
        }
        COMPOSITIONFORM cf;
        cf.dwStyle = CFS_POINT;
        cf.ptCurrentPos.x = pt.x;
        cf.ptCurrentPos.y = pt.y;
        ImmSetCompositionWindow(hImc, &cf);
        HEXOBJ hObj = pWnd->objFocus_;
        if (hObj != 0)
        {
            obj_s *pObj = nullptr;
            INT nError = 0;
            if (_handle_validate(hObj, HT_OBJECT, (LPVOID *)&pObj, &nError))
            {
                LOGFONTW Logfont{0};
                _font_getlogfont(pObj->hFont_, &Logfont);
                ImmSetCompositionFontW(hImc, &Logfont);
                _obj_baseproc(hWnd, hObj, pObj, WM_IME_COMPOSITION, 0, 0);
            }
        }
        ImmReleaseContext(hWnd, hImc);
    }
}

BOOL _wnd_wm_measureitem_host(wnd_s *pWnd, WPARAM wParam, LPARAM lParam)
{
    BOOL ret = FALSE;
    if (wParam == 0) //menu MEASUREITEMSTRUCT https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-measureitemstruct
    {
        if (((MEASUREITEMSTRUCT *)lParam)->CtlType == ODT_MENU)
        {
            INT nID = ((MEASUREITEMSTRUCT *)lParam)->itemID;
            RECT *ppc = (RECT *)pWnd->padding_client_;
            INT offset = 0;
            if (ppc != 0)
            {
                offset = offset + Ex_Scale(ppc->left + ppc->right);
            }
            RECT *ppt = (RECT *)pWnd->padding_text_;
            if (ppt != 0)
            {
                offset = offset + Ex_Scale(ppt->left + ppt->right);
            }
            INT szItemSeparator = pWnd->szItemSeparator_;
            CHAR byte = __get_char(pWnd, offsetof(wnd_s, szItemSeparator_));
            INT width, height;
            if (nID == 0) //MF_SEPARATOR
            {
                width = byte + offset;
                byte = __get_char(pWnd, offsetof(wnd_s, szItemSeparator_) + 3);
                height = byte;
            }
            else
            {
                width = pWnd->menu_maxwidth_ + offset;
                byte = __get_char(pWnd, offsetof(wnd_s, szItemSeparator_) + 1);
                height = byte;
            }
            ((MEASUREITEMSTRUCT *)lParam)->itemWidth = width;
            ((MEASUREITEMSTRUCT *)lParam)->itemHeight = height;
            ret = TRUE;
        }
    }
    return ret;
}

void _wnd_menu_updatecurrent(wnd_s *pWnd)
{

    wnd_s *pHost = pWnd->pMenuHostWnd_;
    if (pHost != 0)
    {
        pHost->pMenuTrackWnd_ = pWnd;
    }
}

BOOL _wnd_menu_mouse(HWND hWnd, wnd_s *pWnd, INT uMsg, WPARAM wParam, LONG_PTR *iItem)
{
    *iItem = -1;
    POINT pt;
    GetCursorPos(&pt);
    _wnd_wm_nchittest(pWnd, hWnd, MAKELONG(pt.x, pt.y));
    _wnd_wm_mouse(pWnd, hWnd, uMsg, wParam, MAKELONG(pt.x, pt.y));
    obj_s *pObj = nullptr;
    INT nError = 0;
    BOOL ret = FALSE;
    if (_handle_validate(pWnd->objHittest_, HT_OBJECT, (LPVOID *)&pObj, &nError))
    {

        if (((pObj->dwStyleEx_ & EOS_EX_FOCUSABLE) == EOS_EX_FOCUSABLE))
        {

            if (((pObj->dwFlags_ & EOF_BMENUITEM) == EOF_BMENUITEM))
            {
                *iItem = pObj->lParam_;
            }
            ret = TRUE;
        }
    }
    _wnd_menu_updatecurrent(pWnd);
    return ret;
}

BOOL _wnd_menu_item_callback(HWND hWnd, HEXOBJ hObj, INT uMsg, WPARAM wParam, LPARAM lParam, LPVOID *lpResult)
{
    return FALSE;
}

BOOL _wnd_menu_callback_test(HWND hWnd, HEXDUI hExDui, INT uMsg, WPARAM wParam, LPARAM lParam, LPVOID *lpResult)
{
    if (uMsg == WM_INITMENUPOPUP)
    {
        RECT rc{0};
        GetWindowRect(hWnd, &rc);
        MoveWindow(hWnd, rc.left, rc.top, 300, 300, FALSE);
        MENUITEMINFOW mii;
        mii.cbSize = sizeof(MENUITEMINFOW);
        mii.fMask = MIIM_FTYPE | MIIM_SUBMENU | MIIM_ID;
        INT nCount = GetMenuItemCount((HMENU)wParam) - 1;
        std::vector<HEXOBJ> aryItems;
        aryItems.resize(nCount);
        INT index = 0;
        for (INT i = 0; i < nCount; i++)
        {
            if (GetMenuItemInfoW((HMENU)wParam, i, TRUE, &mii))
            {
                if ((mii.fType & MFT_SEPARATOR) == 0) //分隔符
                {
                    aryItems[index] = Ex_ObjGetFromID(hExDui, mii.wID);
                    index = index + 1;
                }
            }
        }
        if (index > 0)
        {
            HEXOBJ objEntry = Ex_ObjGetObj(aryItems[0], GW_HWNDFIRST);
        }
        aryItems.resize(index);
        INT radian = 2 * 3.1415926 / index;
        INT radius = 70;
        for (INT j = 0; j < index; j++)
        {
            Ex_ObjMove(aryItems[j], radius + floor(radius * std::cos(j * radian)), radius + floor(radius * std::cos(j * radian)), 44, 44, FALSE);
            Ex_ObjSetLong(aryItems[j], EOL_OBJPROC, (size_t)&_wnd_menu_item_callback);
            Ex_ObjSetColor(aryItems[j], COLOR_EX_BACKGROUND, -872380161, FALSE);
            Ex_ObjSetRadius(aryItems[j], 0, 0, 0, 15, TRUE);
        }
    }
    else if (uMsg == MN_SELECTITEM) //MN_SELECTITEM 测试一下MenuBar切换菜单项的可行性
    {
        POINT pt;
        GetCursorPos(&pt);
        HEXDUI hdui = Ex_DUIFromWindow(WindowFromPoint(pt));
        wnd_s *pdui = nullptr;
        INT nError = 0;
        if (_handle_validate(hdui, HT_DUI, (LPVOID *)&pdui, &nError))
        {
            ScreenToClient(pdui->hWnd_, &pt);
            HEXOBJ hObj = _wnd_wm_nchittest_obj((HWND)pdui->hWnd_, pdui, pdui->objChildLast_, pt.x, pt.y, 0, 0); //有改动
            obj_s *pObj = nullptr;
            if (_handle_validate(hObj, HT_OBJECT, (LPVOID *)&pObj, &nError))
            {
                if (pObj->id_ == 1007)
                {
                    //先判断控件类型为菜单栏
                    // 分发一条消息给控件,判断鼠标命中的位置是不是还是当前的菜单
                    //如果不是了,则EndMenu并弹出新菜单
                    //PostMessageW (__get (nCount, #_wnd_hWnd), 31, 0, 0)  ' WM_CANCELMODE 关闭菜单
                    EndMenu();
                }
            }
        }
    }
    return FALSE;
}

void _wnd_wm_initmenupopup(HWND hWnd, wnd_s *pWnd, HMENU hMenu)
{
    BOOL fChecked = FALSE;
    if (!Flag_Query(EXGF_MENU_ALL))
    {
        LPVOID lpMenuParams = pWnd->lpMenuParams_;
        if (!IsBadReadPtr(lpMenuParams, sizeof(menu_s)))
        {
            if (hMenu == (LPVOID)__get(lpMenuParams, 0))
            {
                fChecked = TRUE;
            }
        }
    }
    else
    {
        fChecked = TRUE;
    }
    if (fChecked)
    {
        INT nCount = GetMenuItemCount(hMenu) - 1;
        HEXCANVAS hCanvas = pWnd->canvas_bkg_;
        HEXFONT hFont = pWnd->hFont_Menu_;

        WCHAR buff[520];
        FLOAT width, height, nMax = 0;
        for (INT i = 0; i < nCount; i++)
        {
            GetMenuStringW(hMenu, i, buff, 520, MF_BYPOSITION);
            _canvas_calctextsize(hCanvas, hFont, buff, -1, DT_SINGLELINE, 0, 0, 0, &width, &height);
            if (nMax < width)
            {
                nMax = width;
            }
        }
        pWnd->menu_maxwidth_ = nMax;
        MENUITEMINFOW mii;
        mii.cbSize = sizeof(MENUITEMINFOW);
        mii.fMask = MIIM_FTYPE | MIIM_ID;
        for (INT i = 0; i < nCount; i++)
        {
            if (GetMenuItemInfoW(hMenu, i, TRUE, &mii))
            {
                if ((mii.fType & MFT_SEPARATOR) != 0)
                {
                    mii.wID = 0;
                }
                mii.fType = mii.fType | MFT_OWNERDRAW;
                if (SetMenuItemInfoW(hMenu, i, TRUE, &mii))
                {
                    continue;
                }
            }
            fChecked = FALSE;
            break;
        }
        if (fChecked)
        {
            if (HashTable_Set(g_Li.hTableLayout, (size_t)hMenu, pWnd->hexdui_))
            {
                pWnd->hMenuPopup_ = hMenu;
                pWnd->dwFlags_ = pWnd->dwFlags_ | EWF_BMENUINITED;
            }
        }
    }
}

BOOL Ex_TrackPopupMenu(HMENU hMenu, DWORD uFlags, INT x, INT y, size_t nReserved, EXHANDLE handle, RECT *lpRC, MsgPROC pfnCallback, DWORD dwFlags)
{
    HWND hWnd = 0;
    wnd_s *pWnd = nullptr;
    menu_s menu{};
    if (_wnd_getfromhandle(handle, &hWnd, &pWnd))
    {
        menu.hMenu_ = hMenu;
        menu.uFlags_ = uFlags;
        menu.x_ = x;
        menu.y_ = y;
        menu.nReserved_ = nReserved;
        menu.handle_ = handle;
        menu.lpRC_ = lpRC;
        menu.pfnCallback_ = pfnCallback;
        menu.dwFlags_ = dwFlags;
        pWnd->lpMenuParams_ = &menu;
    }
    BOOL ret = TrackPopupMenu((HMENU)hMenu, uFlags, x, y, nReserved, hWnd, lpRC);
    return ret;
}

INT Ex_MessageBoxEx(size_t handle, LPCWSTR lpText, LPCWSTR lpCaption, INT uType, LPCWSTR lpCheckBox, BOOL *lpCheckBoxChecked, INT dwMilliseconds, INT dwFlags, MsgPROC lpfnMsgProc)
{
    HWND hWnd = 0;
    wnd_s *pWnd = nullptr;
    mbp_s mbp{};
    if (_wnd_getfromhandle(handle, &hWnd, &pWnd))
    {
        mbp.handle_ = handle;
        mbp.lpText_ = lpText;
        mbp.lpCaption_ = lpCaption;
        mbp.uType_ = uType;
        mbp.lpCheckBox_ = lpCheckBox;
        mbp.lpCheckBoxChecked_ = lpCheckBoxChecked;
        mbp.dwMilliseconds_ = dwMilliseconds;
        mbp.dwFlags_ = dwFlags;
        mbp.lpfnNotifyCallback_ = lpfnMsgProc;

        pWnd->lpMsgParams_ = &mbp;
    }
    auto ret = MessageBoxW(hWnd, lpText, lpCaption, uType);
    return ret;
}

INT Ex_MessageBox(size_t handle, LPCWSTR lpText, LPCWSTR lpCaption, INT uType, INT dwFlags)
{
    return Ex_MessageBoxEx(handle, lpText, lpCaption, uType, 0, 0, 0, dwFlags, 0);
}

BOOL Ex_DUITrayIconPopup(HEXDUI hExDui, LPCWSTR lpwzInfo, LPCWSTR lpwzInfoTitle, INT dwInfoFlags)
{
    wnd_s *pWnd = nullptr;
    INT nError = 0;
    if (_handle_validate(hExDui, HT_DUI, (LPVOID *)&pWnd, &nError))
    {
        LPVOID lpNid = pWnd->lpNid_;
        if (lpNid != 0)
        {
            ((NOTIFYICONDATAW *)lpNid)->uFlags = NIF_INFO;
            RtlZeroMemory((LPVOID)((size_t)lpNid + offsetof(NOTIFYICONDATAW, szInfo)), 512);
            INT len = lstrlenW(lpwzInfo);
            if (len > 255)
                len = 255;
            RtlMoveMemory((LPVOID)((size_t)lpNid + offsetof(NOTIFYICONDATAW, szInfo)), lpwzInfo, len * 2);
            RtlZeroMemory((LPVOID)((size_t)lpNid + offsetof(NOTIFYICONDATAW, szInfoTitle)), 128);
            len = lstrlenW(lpwzInfoTitle);
            if (len > 63)
                len = 63;
            RtlMoveMemory((LPVOID)((size_t)lpNid + offsetof(NOTIFYICONDATAW, szInfoTitle)), lpwzInfoTitle, len * 2);
            ((NOTIFYICONDATAW *)lpNid)->dwInfoFlags = dwInfoFlags;
            Shell_NotifyIconW(NIM_MODIFY, (PNOTIFYICONDATAW)lpNid);
        }
    }
    return nError == 0;
}

BOOL Ex_DUITrayIconSet(HEXDUI hExDui, HICON hIcon, LPCWSTR lpwzTips)
{
    wnd_s *pWnd = nullptr;
    INT nError = 0;
    if (_handle_validate(hExDui, HT_DUI, (LPVOID *)&pWnd, &nError))
    {
        HWND hWnd = pWnd->hWnd_;
        INT len = lstrlenW(lpwzTips);
        LPVOID lpNid = pWnd->lpNid_;
        if (lpNid == 0)
        {
            if (hIcon == 0)
            {
                hIcon = _wnd_geticonhandle(hWnd, FALSE);
            }
            LPVOID lpNid = Ex_MemAlloc(sizeof(NOTIFYICONDATAW));

            ((NOTIFYICONDATAW *)lpNid)->cbSize = sizeof(NOTIFYICONDATAW);
            ((NOTIFYICONDATAW *)lpNid)->hWnd = hWnd;
            ((NOTIFYICONDATAW *)lpNid)->uID = 1;
            ((NOTIFYICONDATAW *)lpNid)->uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP | NIF_SHOWTIP;
            ((NOTIFYICONDATAW *)lpNid)->uCallbackMessage = g_Li.dwMessage;
            ((NOTIFYICONDATAW *)lpNid)->hIcon = hIcon;
            ((NOTIFYICONDATAW*)lpNid)->uVersion = NOTIFYICON_VERSION_4;
            if (len != 0)
            {
                if (len > 127)
                    len = 127;
                RtlMoveMemory((LPVOID)((size_t)lpNid + offsetof(NOTIFYICONDATAW, szTip)), lpwzTips, len * 2);
            }
            Shell_NotifyIconW(NIM_ADD, (PNOTIFYICONDATAW)lpNid);
            pWnd->lpNid_ = lpNid;
        }
        else
        {
            INT uFlags = 0;
            if (len != 0)
            {
                if (len > 127)
                    len = 127;
                RtlZeroMemory((LPVOID)((size_t)lpNid + offsetof(NOTIFYICONDATAW, szTip)), 127);
                RtlMoveMemory((LPVOID)((size_t)lpNid + offsetof(NOTIFYICONDATAW, szTip)), lpwzTips, len * 2);
                uFlags = NIF_TIP;
            }
            if (hIcon != 0)
            {
                ((NOTIFYICONDATAW *)lpNid)->hIcon = (HICON)hIcon;
                uFlags = uFlags | NIF_ICON;
            }
            if (uFlags != 0)
            {
                ((NOTIFYICONDATAW *)lpNid)->uFlags = uFlags;
                Shell_NotifyIconW(NIM_MODIFY, (PNOTIFYICONDATAW)lpNid);
            }
        }
    }
    Ex_SetLastError(nError);
    return nError == 0;
}

BOOL Ex_DUIGetBackgroundImage(HEXDUI hExDui, LPVOID lpBackgroundImage)
{
    wnd_s *pWnd = nullptr;
    INT nError = 0;
    if (_handle_validate(hExDui, HT_DUI, (LPVOID *)&pWnd, &nError))
    {
        if (IsBadWritePtr(lpBackgroundImage, sizeof(EX_BACKGROUNDIMAGEINFO)))
        {
            nError = ERROR_EX_MEMORY_BADPTR;
        }
        else
        {
            RtlMoveMemory(lpBackgroundImage, pWnd->lpBackgroundImage_, sizeof(EX_BACKGROUNDIMAGEINFO));
        }
    }
    Ex_SetLastError(nError);
    return nError == 0;
}

void _wnd_getclientrect(wnd_s *pWnd, RECT *lpRect, INT *nError)
{
    if (IsBadWritePtr(lpRect, 16))
    {
        *nError = ERROR_EX_BAD_SIZE;
    }
    else
    {
        RtlZeroMemory(lpRect, 16);
        lpRect->right = pWnd->width_;
        lpRect->bottom = pWnd->height_;
        if (Flag_Query(EXGF_DPI_ENABLE))
        {
            lpRect->right = (FLOAT)lpRect->right / g_Li.DpiX;
            lpRect->bottom = (FLOAT)lpRect->bottom / g_Li.DpiY;
        }
    }
}

BOOL Ex_DUIGetClientRect(HEXDUI hExDui, RECT *lpClientRect)
{
    wnd_s *pWnd = nullptr;
    INT nError = 0;
    if (_handle_validate(hExDui, HT_DUI, (LPVOID *)&pWnd, &nError))
    {
        _wnd_getclientrect(pWnd, lpClientRect, &nError);
    }
    return nError == 0;
}

size_t Ex_DUIGetLong(HEXDUI hExDui, INT nIndex)
{
    wnd_s *pWnd = nullptr;
    INT nError = 0;
    size_t ret = 0;
    if (_handle_validate(hExDui, HT_DUI, (LPVOID *)&pWnd, &nError))
    {
        if (nIndex == EWL_ALPHA)
        {
            ret = pWnd->alpha_;
        }
        else if (nIndex == EWL_BLUR)
        {
            ret = pWnd->fBlur_;
        }
        else if (nIndex == EWL_CRBKG)
        {
            ret = (size_t)pWnd->crBkg_;
        }
        else if (nIndex == EWL_CRBORDER)
        {
            ret = (size_t)pWnd->crBorder_;
        }
        else if (nIndex == EWL_HTHEME)
        {
            ret = (size_t)pWnd->hTheme_;
        }
        else if (nIndex == EWL_HWND)
        {
            ret = (size_t)pWnd->hWnd_;
        }
        else if (nIndex == EWL_LPARAM)
        {
            ret = pWnd->lParam_;
        }
        else if (nIndex == EWL_MINHEIGHT)
        {
            ret = pWnd->minHeight_;
        }
        else if (nIndex == EWL_MINWIDTH)
        {
            ret = pWnd->minWidth_;
        }
        else if (nIndex == EWL_MSGPROC)
        {
            ret = (size_t)pWnd->pfnMsgProc_;
        }
        else if (nIndex == EWL_OBJCAPTION)
        {
            ret = (size_t)pWnd->objCaption_;
        }
        else if (nIndex == EWL_OBJFOCUS)
        {
            ret = (size_t)pWnd->objFocus_;
        }
        else if (nIndex == EWL_RADIUS)
        {
            ret = (size_t)pWnd->Radius_;
        }
        else if (nIndex == -143)
        {
            ret = (size_t)pWnd->vol_wndptr_;
        }
        else
        {
            EX_ASSERT(false, L"Ex_DUIGetLong: unknown EWL index: %ld", nIndex);
        }
    }
    Ex_SetLastError(nError);
    return ret;
}

size_t Ex_DUISetLong(HEXDUI hExDui, INT nIndex, size_t dwNewLong)
{
    wnd_s *pWnd = nullptr;
    INT nError = 0;
    size_t ret = 0;
    if (_handle_validate(hExDui, HT_DUI, (LPVOID *)&pWnd, &nError))
    {
        BOOL bRedraw = FALSE;
        if (nIndex == EWL_ALPHA)
        {
            ret = (size_t)pWnd->alpha_;
            pWnd->alpha_ = dwNewLong;
            FLAGS_DEL(pWnd->dwFlags_, EWF_BRENDERED); //强制阴影重画
        }
        else if (nIndex == EWL_BLUR)
        {
            ret = pWnd->fBlur_;
            pWnd->fBlur_ = dwNewLong;
            bRedraw = TRUE;
        }
        else if (nIndex == EWL_CRBKG)
        {
            ret = (size_t)pWnd->crBkg_;
            pWnd->crBkg_ = dwNewLong;
            pWnd->dwStyle_ = pWnd->dwStyle_ | EWS_NOINHERITBKG;
            bRedraw = TRUE;
        }
        else if (nIndex == EWL_CRBORDER)
        {
            ret = (size_t)pWnd->crBorder_;
            pWnd->crBorder_ = dwNewLong;
            bRedraw = TRUE;
        }
        else if (nIndex == EWL_HTHEME)
        {
            ret = (size_t)pWnd->hTheme_;
            pWnd->hTheme_ = (HEXTHEME)dwNewLong;
            bRedraw = TRUE;
        }
        else if (nIndex == EWL_HWND)
        {
            ret = (size_t)pWnd->hWnd_;
            pWnd->hWnd_ = (HWND)dwNewLong;
        }
        else if (nIndex == EWL_LPARAM)
        {
            ret = pWnd->lParam_;
            pWnd->lParam_ = dwNewLong;
        }
        else if (nIndex == EWL_MINHEIGHT)
        {
            ret = pWnd->minHeight_;
            pWnd->minHeight_ = dwNewLong;
            bRedraw = TRUE;
        }
        else if (nIndex == EWL_MINWIDTH)
        {
            ret = pWnd->minWidth_;
            pWnd->minWidth_ = dwNewLong;
            bRedraw = TRUE;
        }
        else if (nIndex == EWL_MSGPROC)
        {
            ret = (size_t)pWnd->pfnMsgProc_;
            pWnd->pfnMsgProc_ = (WinMsgPROC)dwNewLong;
            bRedraw = TRUE;
        }
        else if (nIndex == EWL_OBJCAPTION)
        {
            ret = pWnd->objCaption_;
            pWnd->objCaption_ = dwNewLong;
            bRedraw = TRUE;
        }
        else if (nIndex == EWL_OBJFOCUS)
        {
            ret = pWnd->objFocus_;
            pWnd->objFocus_ = dwNewLong;
            bRedraw = TRUE;
        }
        else if (nIndex == EWL_CRSD)
        {
            ret = (size_t)pWnd->crSD_;
            pWnd->crSD_ = dwNewLong;
            bRedraw = TRUE;
        }
        else if (nIndex == EWL_RADIUS)
        {
            ret = (size_t)pWnd->Radius_;
            pWnd->Radius_ = dwNewLong;
            bRedraw = TRUE;
        }
        else if (nIndex == -143)
        {
            ret = (size_t)pWnd->vol_wndptr_;
            pWnd->vol_wndptr_ = (void*)dwNewLong;
            bRedraw = TRUE;
        }
        else
        {
            EX_ASSERT(false, L"Ex_DUISetLong: unknown EWL index: %ld", nIndex);
        }
        if (bRedraw)
        {
            pWnd->dwFlags_ = pWnd->dwFlags_ | EWF_BREDRAWBACKGROUND;
            _wnd_redraw_bkg(pWnd->hWnd_, pWnd, 0, TRUE, FALSE);
        }
    }
    Ex_SetLastError(nError);
    return ret;
}

BOOL Ex_DUIShowWindowEx(HEXDUI hExDui, INT nCmdShow, INT dwTimer, INT dwFrames, INT dwFlags, INT uEasing, WPARAM wParam, LPARAM lParam)
{
    wnd_s *pWnd = nullptr;
    INT nError = 0;
    BOOL ret = FALSE;
    if (_handle_validate(hExDui, HT_DUI, (LPVOID *)&pWnd, &nError))
    {
        HWND hWnd = pWnd->hWnd_;
        //刷新组件层
        pWnd->dwFlags_ = pWnd->dwFlags_ | EWF_INTED;
        if (FLAGS_CHECK(pWnd->dwStyle_, EWS_POPUPWINDOW))
        { //弹出窗不获取焦点
            nCmdShow = SW_SHOWNOACTIVATE;
        }
        ret = ShowWindow(hWnd, nCmdShow);
        if (GetFocus() == hWnd)
        {
            FLAGS_ADD(pWnd->dwFlags_, EWF_ACTIVE);
        }
        auto atomName = GetClassLongPtrW(hWnd, GCW_ATOM);
        if (atomName == ATOM_DIALOG) //判断是模态窗口,添加模态窗口风格
        {
            SetFocus(hWnd);
        }
        ret = InvalidateRect(hWnd, NULL, FALSE);
        ret = UpdateWindow(hWnd);
    }
    Ex_SetLastError(nError);
    return ret;
}

BOOL Ex_DUIShowWindow(HEXDUI hExDui, INT nCmdShow, INT dwTimer, INT dwFrames, INT dwFlags)
{
    return Ex_DUIShowWindowEx(hExDui, nCmdShow, dwTimer, dwFrames, dwFlags, 0, 0, 0);
}

HEXDUI Ex_DUIBindWindowEx(HWND hWnd, HEXTHEME hTheme, DWORD dwStyle, LPARAM lParam, WinMsgPROC lpfnMsgProc)
{
    INT nError = 0;
    wnd_s *pWnd = nullptr;
    HEXDUI hExDui = 0;
    if (IsWindow(hWnd))
    {
        pWnd = (wnd_s *)Ex_MemAlloc(sizeof(wnd_s));
        if (pWnd != 0)
        {
            hExDui = _handle_create(HT_DUI, pWnd, &nError);

            if (hExDui != 0)
            {
                nError = _wnd_create(hExDui, pWnd, hWnd, dwStyle, hTheme, lParam, lpfnMsgProc);
            }
        }
        else
        {
            nError = ERROR_EX_MEMORY_ALLOC;
        }
    }
    else
    {
        nError = GetLastError();
    }
    if (nError != 0)
    {
        EX_ASSERT(FALSE, L"wnd create error: %02X", nError);
        if (pWnd != 0)
        {
            Ex_MemFree(pWnd);
        }
        if (hExDui != 0)
        {
            nError = 0;
            _handle_destroy(hExDui, &nError);
        }
    }
    Ex_SetLastError(nError);
    return hExDui;
}

HEXDUI Ex_DUIBindWindow(HWND hWnd, HEXTHEME hTheme, DWORD dwStyle)
{
    return Ex_DUIBindWindowEx(hWnd, hTheme, dwStyle, 0, 0);
}

HEXOBJ Ex_DUIGetObjFromPoint(EXHANDLE handle, INT x, INT y)
{
    wnd_s *pWnd;
    RECT rect = {0};
    HWND hWnd = 0;
    obj_s *pObj = 0;
    POINT point{x, y};
    if (!handle)
    {
        GetCursorPos(&point);
        HWND hWnd = WindowFromPoint(point);
        if (hWnd)
        {
            GetWindowRect(hWnd, &rect);
            point.x -= rect.left;
            point.y -= rect.top;
        }
    }
    else if (_wnd_getfromhandle((size_t)handle, &hWnd, &pWnd))
    {
        INT hitCode = 0;
        _wnd_wm_nchittest_obj(hWnd, pWnd, pWnd->objChildLast_, point.x, point.y, &hitCode, &pObj);
        if (pObj)
        {
            return pObj->hObj_;
        }
    }
    return 0;
}